Cycles Volume Render: work on nodes and closures.
[blender.git] / intern / cycles / kernel / closure / volume.h
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16
17 #ifndef __VOLUME_H__
18 #define __VOLUME_H__
19
20 CCL_NAMESPACE_BEGIN
21
22 /* HENYEY-GREENSTEIN CLOSURE */
23
24 /* Given cosine between rays, return probability density that a photon bounces
25  * to that direction. The g parameter controls how different it is from the
26  * uniform sphere. g=0 uniform diffuse-like, g=1 close to sharp single ray. */
27 ccl_device float single_peaked_henyey_greenstein(float cos_theta, float g)
28 {
29         if(fabsf(g) < 1e-3f)
30                 return M_1_PI_F * 0.25f;
31         
32         return ((1.0f - g * g) / safe_powf(1.0f + g * g - 2.0f * g * cos_theta, 1.5f)) * (M_1_PI_F * 0.25f);
33 };
34
35 ccl_device int volume_henyey_greenstein_setup(ShaderClosure *sc)
36 {
37         sc->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
38         
39         /* clamp anisotropy to avoid delta function */
40         sc->data0 = signf(sc->data0) * min(fabsf(sc->data0), 1.0f - 1e-3f);
41
42         return SD_BSDF|SD_BSDF_HAS_EVAL;
43 }
44
45 ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, const float3 I, float3 omega_in, float *pdf)
46 {
47         float g = sc->data0;
48
49         /* note that I points towards the viewer */
50         float cos_theta = dot(-I, omega_in);
51
52         *pdf = single_peaked_henyey_greenstein(cos_theta, g);
53
54         return make_float3(*pdf, *pdf, *pdf);
55 }
56
57 ccl_device int volume_henyey_greenstein_sample(const ShaderClosure *sc, float3 I, float3 dIdx, float3 dIdy, float randu, float randv,
58         float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
59 {
60         float g = sc->data0;
61         float cos_phi, sin_phi, cos_theta;
62
63         /* match pdf for small g */
64         if(fabsf(g) < 1e-3f) {
65                 cos_theta = (1.0f - 2.0f * randu);
66         }
67         else {
68                 float k = (1.0f - g * g) / (1.0f - g + 2.0f * g * randu);
69                 cos_theta = (1.0f + g * g - k * k) / (2.0f * g);
70         }
71
72         float sin_theta = safe_sqrtf(1.0f - cos_theta * cos_theta);
73
74         float phi = M_2PI_F * randv;
75         cos_phi = cosf(phi);
76         sin_phi = sinf(phi);
77
78         /* note that I points towards the viewer and so is used negated */
79         float3 T, B;
80         make_orthonormals(-I, &T, &B);
81         *omega_in = sin_theta * cos_phi * T + sin_theta * sin_phi * B + cos_theta * (-I);
82
83         *pdf = single_peaked_henyey_greenstein(cos_theta, g);
84         *eval = make_float3(*pdf, *pdf, *pdf); /* perfect importance sampling */
85
86 #ifdef __RAY_DIFFERENTIALS__
87         /* todo: implement ray differential estimation */
88         *domega_in_dx = make_float3(0.0f, 0.0f, 0.0f);
89         *domega_in_dy = make_float3(0.0f, 0.0f, 0.0f);
90 #endif
91
92         return LABEL_VOLUME_SCATTER;
93 }
94
95 /* ABSORPTION VOLUME CLOSURE */
96
97 ccl_device int volume_absorption_setup(ShaderClosure *sc)
98 {
99         sc->type = CLOSURE_VOLUME_ABSORPTION_ID;
100
101         return SD_VOLUME;
102 }
103
104 /* VOLUME CLOSURE */
105
106 ccl_device float3 volume_eval_phase(const ShaderClosure *sc, const float3 I, float3 omega_in, float *pdf)
107 {
108         float3 eval;
109
110         switch(sc->type) {
111                 case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
112                         eval = volume_henyey_greenstein_eval_phase(sc, I, omega_in, pdf);
113                         break;
114                 default:
115                         eval = make_float3(0.0f, 0.0f, 0.0f);
116                         break;
117         }
118
119         return eval;
120 }
121
122 ccl_device int volume_sample(const ShaderData *sd, const ShaderClosure *sc, float randu,
123         float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
124 {
125         int label;
126
127         switch(sc->type) {
128                 case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
129                         label = volume_henyey_greenstein_sample(sc, sd->I, sd->dI.dx, sd->dI.dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
130                         break;
131                 default:
132                         *eval = make_float3(0.0f, 0.0f, 0.0f);
133                         label = LABEL_NONE;
134                         break;
135         }
136
137         return label;
138 }
139
140 CCL_NAMESPACE_END
141
142 #endif