Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/intern
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2013-12-28 04:54:44 +0400
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2013-12-28 19:57:02 +0400
commita35db17cee5a9b47dc9624f7dfcb41f5fc185b33 (patch)
treeef23032da73b9b202490307f865e2afd4e2e7e76 /intern
parenta06c9c277a8577f7ef473fffaf2258d2a3a6ab80 (diff)
Cycles Volume Render: work on nodes and closures.
* Henyey-Greenstein scattering closure implementation. * Rename transparent to absorption node and isotropic to scatter node. * Volume density is folded into the closure weights. * OSL support for volume closures and nodes. * This commit has no user visible changes, there is no volume render code yet. This is work by "storm", Stuart Broadfoot, Thomas Dinges and myself.
Diffstat (limited to 'intern')
-rw-r--r--intern/cycles/app/cycles_xml.cpp8
-rw-r--r--intern/cycles/blender/blender_shader.cpp8
-rw-r--r--intern/cycles/kernel/closure/volume.h114
-rw-r--r--intern/cycles/kernel/kernel_shader.h6
-rw-r--r--intern/cycles/kernel/kernel_types.h20
-rw-r--r--intern/cycles/kernel/osl/osl_closures.cpp13
-rw-r--r--intern/cycles/kernel/osl/osl_closures.h50
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp21
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt2
-rw-r--r--intern/cycles/kernel/shaders/node_absorption_volume.osl26
-rw-r--r--intern/cycles/kernel/shaders/node_light_path.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_scatter_volume.osl27
-rw-r--r--intern/cycles/kernel/shaders/stdosl.h5
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h23
-rw-r--r--intern/cycles/kernel/svm/svm_light_path.h1
-rw-r--r--intern/cycles/kernel/svm/svm_types.h9
-rw-r--r--intern/cycles/render/nodes.cpp37
-rw-r--r--intern/cycles/render/nodes.h8
-rw-r--r--intern/cycles/render/osl.cpp19
19 files changed, 306 insertions, 93 deletions
diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp
index df187f046e5..a483c766bed 100644
--- a/intern/cycles/app/cycles_xml.cpp
+++ b/intern/cycles/app/cycles_xml.cpp
@@ -452,11 +452,11 @@ static void xml_read_shader_graph(const XMLReadState& state, Shader *shader, pug
else if(string_iequals(node.name(), "background")) {
snode = new BackgroundNode();
}
- else if(string_iequals(node.name(), "transparent_volume")) {
- snode = new TransparentVolumeNode();
+ else if(string_iequals(node.name(), "absorption_volume")) {
+ snode = new AbsorptionVolumeNode();
}
- else if(string_iequals(node.name(), "isotropic_volume")) {
- snode = new IsotropicVolumeNode();
+ else if(string_iequals(node.name(), "scatter_volume")) {
+ snode = new ScatterVolumeNode();
}
else if(string_iequals(node.name(), "geometry")) {
snode = new GeometryNode();
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index a6d2b537bc7..0c3a32af20d 100644
--- a/intern/cycles/blender/blender_shader.cpp
+++ b/intern/cycles/blender/blender_shader.cpp
@@ -422,11 +422,11 @@ static ShaderNode *add_node(Scene *scene, BL::BlendData b_data, BL::Scene b_scen
else if (b_node.is_a(&RNA_ShaderNodeAmbientOcclusion)) {
node = new AmbientOcclusionNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeVolumeIsotropic)) {
- node = new IsotropicVolumeNode();
+ else if (b_node.is_a(&RNA_ShaderNodeVolumeScatter)) {
+ node = new ScatterVolumeNode();
}
- else if (b_node.is_a(&RNA_ShaderNodeVolumeTransparent)) {
- node = new TransparentVolumeNode();
+ else if (b_node.is_a(&RNA_ShaderNodeVolumeAbsorption)) {
+ node = new AbsorptionVolumeNode();
}
else if (b_node.is_a(&RNA_ShaderNodeNewGeometry)) {
node = new GeometryNode();
diff --git a/intern/cycles/kernel/closure/volume.h b/intern/cycles/kernel/closure/volume.h
index f4932568c1f..dae24fb03fd 100644
--- a/intern/cycles/kernel/closure/volume.h
+++ b/intern/cycles/kernel/closure/volume.h
@@ -14,53 +14,102 @@
* limitations under the License
*/
+#ifndef __VOLUME_H__
+#define __VOLUME_H__
+
CCL_NAMESPACE_BEGIN
-/* note: the interfaces here are just as an example, need to figure
- * out the right functions and parameters to use */
+/* HENYEY-GREENSTEIN CLOSURE */
-/* ISOTROPIC VOLUME CLOSURE */
+/* Given cosine between rays, return probability density that a photon bounces
+ * to that direction. The g parameter controls how different it is from the
+ * uniform sphere. g=0 uniform diffuse-like, g=1 close to sharp single ray. */
+ccl_device float single_peaked_henyey_greenstein(float cos_theta, float g)
+{
+ if(fabsf(g) < 1e-3f)
+ return M_1_PI_F * 0.25f;
+
+ return ((1.0f - g * g) / safe_powf(1.0f + g * g - 2.0f * g * cos_theta, 1.5f)) * (M_1_PI_F * 0.25f);
+};
-ccl_device int volume_isotropic_setup(ShaderClosure *sc, float density)
+ccl_device int volume_henyey_greenstein_setup(ShaderClosure *sc)
{
- sc->type = CLOSURE_VOLUME_ISOTROPIC_ID;
- sc->data0 = density;
+ sc->type = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
+
+ /* clamp anisotropy to avoid delta function */
+ sc->data0 = signf(sc->data0) * min(fabsf(sc->data0), 1.0f - 1e-3f);
- return SD_VOLUME;
+ return SD_BSDF|SD_BSDF_HAS_EVAL;
}
-ccl_device float3 volume_isotropic_eval_phase(const ShaderClosure *sc, const float3 omega_in, const float3 omega_out)
+ccl_device float3 volume_henyey_greenstein_eval_phase(const ShaderClosure *sc, const float3 I, float3 omega_in, float *pdf)
{
- return make_float3(1.0f, 1.0f, 1.0f);
-}
+ float g = sc->data0;
-/* TRANSPARENT VOLUME CLOSURE */
+ /* note that I points towards the viewer */
+ float cos_theta = dot(-I, omega_in);
-ccl_device int volume_transparent_setup(ShaderClosure *sc, float density)
+ *pdf = single_peaked_henyey_greenstein(cos_theta, g);
+
+ return make_float3(*pdf, *pdf, *pdf);
+}
+
+ccl_device int volume_henyey_greenstein_sample(const ShaderClosure *sc, 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)
{
- sc->type = CLOSURE_VOLUME_TRANSPARENT_ID;
- sc->data0 = density;
+ float g = sc->data0;
+ float cos_phi, sin_phi, cos_theta;
- return SD_VOLUME;
+ /* match pdf for small g */
+ if(fabsf(g) < 1e-3f) {
+ cos_theta = (1.0f - 2.0f * randu);
+ }
+ else {
+ float k = (1.0f - g * g) / (1.0f - g + 2.0f * g * randu);
+ cos_theta = (1.0f + g * g - k * k) / (2.0f * g);
+ }
+
+ float sin_theta = safe_sqrtf(1.0f - cos_theta * cos_theta);
+
+ float phi = M_2PI_F * randv;
+ cos_phi = cosf(phi);
+ sin_phi = sinf(phi);
+
+ /* note that I points towards the viewer and so is used negated */
+ float3 T, B;
+ make_orthonormals(-I, &T, &B);
+ *omega_in = sin_theta * cos_phi * T + sin_theta * sin_phi * B + cos_theta * (-I);
+
+ *pdf = single_peaked_henyey_greenstein(cos_theta, g);
+ *eval = make_float3(*pdf, *pdf, *pdf); /* perfect importance sampling */
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* todo: implement ray differential estimation */
+ *domega_in_dx = make_float3(0.0f, 0.0f, 0.0f);
+ *domega_in_dy = make_float3(0.0f, 0.0f, 0.0f);
+#endif
+
+ return LABEL_VOLUME_SCATTER;
}
-ccl_device float3 volume_transparent_eval_phase(const ShaderClosure *sc, const float3 omega_in, const float3 omega_out)
+/* ABSORPTION VOLUME CLOSURE */
+
+ccl_device int volume_absorption_setup(ShaderClosure *sc)
{
- return make_float3(1.0f, 1.0f, 1.0f);
+ sc->type = CLOSURE_VOLUME_ABSORPTION_ID;
+
+ return SD_VOLUME;
}
/* VOLUME CLOSURE */
-ccl_device float3 volume_eval_phase(KernelGlobals *kg, const ShaderClosure *sc, const float3 omega_in, const float3 omega_out)
+ccl_device float3 volume_eval_phase(const ShaderClosure *sc, const float3 I, float3 omega_in, float *pdf)
{
float3 eval;
switch(sc->type) {
- case CLOSURE_VOLUME_ISOTROPIC_ID:
- eval = volume_isotropic_eval_phase(sc, omega_in, omega_out);
- break;
- case CLOSURE_VOLUME_TRANSPARENT_ID:
- eval = volume_transparent_eval_phase(sc, omega_in, omega_out);
+ case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
+ eval = volume_henyey_greenstein_eval_phase(sc, I, omega_in, pdf);
break;
default:
eval = make_float3(0.0f, 0.0f, 0.0f);
@@ -70,5 +119,24 @@ ccl_device float3 volume_eval_phase(KernelGlobals *kg, const ShaderClosure *sc,
return eval;
}
+ccl_device int volume_sample(const ShaderData *sd, const ShaderClosure *sc, float randu,
+ float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
+{
+ int label;
+
+ switch(sc->type) {
+ case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID:
+ 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);
+ break;
+ default:
+ *eval = make_float3(0.0f, 0.0f, 0.0f);
+ label = LABEL_NONE;
+ break;
+ }
+
+ return label;
+}
+
CCL_NAMESPACE_END
+#endif
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 457a7f704c8..012aa4a7e19 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -868,17 +868,19 @@ ccl_device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,
{
#ifdef __MULTI_CLOSURE__
float3 eval = make_float3(0.0f, 0.0f, 0.0f);
+ float pdf;
for(int i = 0; i< sd->num_closure; i++) {
const ShaderClosure *sc = &sd->closure[i];
if(CLOSURE_IS_VOLUME(sc->type))
- eval += volume_eval_phase(kg, sc, omega_in, omega_out);
+ eval += volume_eval_phase(sc, omega_in, omega_out, &pdf);
}
return eval;
#else
- return volume_eval_phase(kg, &sd->closure, omega_in, omega_out);
+ float pdf;
+ return volume_eval_phase(&sd->closure, omega_in, omega_out, &pdf);
#endif
}
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 9b1893e8baa..4821a1b482c 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -201,6 +201,7 @@ enum PathRayFlag {
PATH_RAY_GLOSSY = 16,
PATH_RAY_SINGULAR = 32,
PATH_RAY_TRANSPARENT = 64,
+ PATH_RAY_VOLUME_SCATTER = 128,
PATH_RAY_SHADOW_OPAQUE = 128,
PATH_RAY_SHADOW_TRANSPARENT = 256,
@@ -224,18 +225,13 @@ enum PathRayFlag {
typedef enum ClosureLabel {
LABEL_NONE = 0,
- LABEL_CAMERA = 1,
- LABEL_LIGHT = 2,
- LABEL_BACKGROUND = 4,
- LABEL_TRANSMIT = 8,
- LABEL_REFLECT = 16,
- LABEL_VOLUME = 32,
- LABEL_OBJECT = 64,
- LABEL_DIFFUSE = 128,
- LABEL_GLOSSY = 256,
- LABEL_SINGULAR = 512,
- LABEL_TRANSPARENT = 1024,
- LABEL_STOP = 2048
+ LABEL_TRANSMIT = 1,
+ LABEL_REFLECT = 2,
+ LABEL_DIFFUSE = 4,
+ LABEL_GLOSSY = 8,
+ LABEL_SINGULAR = 16,
+ LABEL_TRANSPARENT = 32,
+ LABEL_VOLUME_SCATTER = 64,
} ClosureLabel;
/* Render Passes */
diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp
index 340e4492584..a96c0e2b1fb 100644
--- a/intern/cycles/kernel/osl/osl_closures.cpp
+++ b/intern/cycles/kernel/osl/osl_closures.cpp
@@ -55,6 +55,7 @@
#include "closure/bsdf_westin.h"
#include "closure/bsdf_toon.h"
#include "closure/bsdf_hair.h"
+#include "closure/volume.h"
CCL_NAMESPACE_BEGIN
@@ -169,6 +170,13 @@ BSDF_CLOSURE_CLASS_BEGIN(HairTransmission, hair_transmission, hair_transmission,
#endif
BSDF_CLOSURE_CLASS_END(HairTransmission, hair_transmission)
+VOLUME_CLOSURE_CLASS_BEGIN(VolumeHenyeyGreenstein, henyey_greenstein, LABEL_VOLUME_SCATTER)
+ CLOSURE_FLOAT_PARAM(VolumeHenyeyGreensteinClosure, sc.data0),
+VOLUME_CLOSURE_CLASS_END(VolumeHenyeyGreenstein, henyey_greenstein)
+
+VOLUME_CLOSURE_CLASS_BEGIN(VolumeAbsorption, absorption, LABEL_SINGULAR)
+VOLUME_CLOSURE_CLASS_END(VolumeAbsorption, absorption)
+
/* Registration */
static void register_closure(OSL::ShadingSystem *ss, const char *name, int id, OSL::ClosureParam *params, OSL::PrepareClosureFunc prepare)
@@ -248,6 +256,11 @@ void OSLShader::register_closures(OSLShadingSystem *ss_)
bsdf_hair_reflection_params(), bsdf_hair_reflection_prepare);
register_closure(ss, "hair_transmission", id++,
bsdf_hair_transmission_params(), bsdf_hair_transmission_prepare);
+
+ register_closure(ss, "henyey_greenstein", id++,
+ volume_henyey_greenstein_params(), volume_henyey_greenstein_prepare);
+ register_closure(ss, "absorption", id++,
+ volume_absorption_params(), volume_absorption_prepare);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h
index b6c38e01b23..f2f79f80fdf 100644
--- a/intern/cycles/kernel/osl/osl_closures.h
+++ b/intern/cycles/kernel/osl/osl_closures.h
@@ -54,6 +54,7 @@ OSL::ClosureParam *closure_bssrdf_cubic_params();
OSL::ClosureParam *closure_bssrdf_gaussian_params();
OSL::ClosureParam *closure_bssrdf_cubic_extended_params();
OSL::ClosureParam *closure_bssrdf_gaussian_extended_params();
+OSL::ClosureParam *closure_henyey_greenstein_volume_params();
void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
void closure_background_prepare(OSL::RendererServices *, int id, void *data);
@@ -65,6 +66,7 @@ void closure_westin_backscatter_prepare(OSL::RendererServices *, int id, void *d
void closure_westin_sheen_prepare(OSL::RendererServices *, int id, void *data);
void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data);
void closure_bssrdf_gaussian_prepare(OSL::RendererServices *, int id, void *data);
+void closure_henyey_greenstein_volume_prepare(OSL::RendererServices *, int id, void *data);
#define CCLOSURE_PREPARE(name, classname) \
void name(RendererServices *, int id, void *data) \
@@ -186,6 +188,54 @@ static ClosureParam *bsdf_##lower##_params() \
\
CCLOSURE_PREPARE_STATIC(bsdf_##lower##_prepare, Upper##Closure)
+
+/* Volume */
+
+class CVolumeClosure : public CClosurePrimitive {
+public:
+ ShaderClosure sc;
+
+ CVolumeClosure(int scattering) : CClosurePrimitive(Volume),
+ m_scattering_label(scattering), m_shaderdata_flag(0)
+ { memset(&sc, 0, sizeof(sc)); }
+ ~CVolumeClosure() { }
+
+ int scattering() const { return m_scattering_label; }
+ int shaderdata_flag() const { return m_shaderdata_flag; }
+
+protected:
+ int m_scattering_label;
+ int m_shaderdata_flag;
+};
+
+#define VOLUME_CLOSURE_CLASS_BEGIN(Upper, lower, TYPE) \
+\
+class Upper##Closure : public CVolumeClosure { \
+public: \
+ Upper##Closure() : CVolumeClosure(TYPE) {} \
+\
+ void setup() \
+ { \
+ sc.prim = NULL; \
+ m_shaderdata_flag = volume_##lower##_setup(&sc); \
+ } \
+}; \
+\
+static ClosureParam *volume_##lower##_params() \
+{ \
+ static ClosureParam params[] = {
+
+/* parameters */
+
+#define VOLUME_CLOSURE_CLASS_END(Upper, lower) \
+ CLOSURE_STRING_KEYPARAM("label"), \
+ CLOSURE_FINISH_PARAM(Upper##Closure) \
+ }; \
+ return params; \
+} \
+\
+CCLOSURE_PREPARE_STATIC(volume_##lower##_prepare, Upper##Closure)
+
CCL_NAMESPACE_END
#endif /* __OSL_CLOSURES_H__ */
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index b0461013239..4358d3f2e76 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -187,7 +187,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
#endif
/* add */
- if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE) {
+ if(sc.sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) {
sd->closure[sd->num_closure++] = sc;
sd->flag |= bsdf->shaderdata_flag();
}
@@ -243,7 +243,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag,
CBSSRDFClosure *bssrdf = (CBSSRDFClosure *)prim;
float sample_weight = fabsf(average(weight));
- if(sample_weight > 1e-5f && sd->num_closure+2 < MAX_CLOSURE) {
+ if(sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure+2 < MAX_CLOSURE) {
sc.sample_weight = sample_weight;
sc.type = bssrdf->sc.type;
@@ -401,18 +401,21 @@ static void flatten_volume_closure_tree(ShaderData *sd,
switch (prim->category) {
case CClosurePrimitive::Volume: {
+ CVolumeClosure *volume = (CVolumeClosure *)prim;
/* sample weight */
float sample_weight = fabsf(average(weight));
sc.sample_weight = sample_weight;
- sc.type = CLOSURE_VOLUME_ID;
- sc.data0 = 0.0f;
- sc.data1 = 0.0f;
- sc.prim = NULL;
+ sc.type = volume->sc.type;
+ sc.data0 = volume->sc.data0;
+ sc.data1 = volume->sc.data1;
/* add */
- if(sc.sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE)
+ if(sc.sample_weight > CLOSURE_WEIGHT_CUTOFF &&
+ sd->num_closure < MAX_CLOSURE) {
sd->closure[sd->num_closure++] = sc;
+ sd->flag |= volume->shaderdata_flag();
+ }
break;
}
case CClosurePrimitive::Holdout:
@@ -451,6 +454,10 @@ void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int
if (kg->osl->volume_state[shader])
ss->execute(*octx, *(kg->osl->volume_state[shader]), *globals);
+
+ /* flatten closure tree */
+ sd->num_closure = 0;
+ sd->randb_closure = randb;
if (globals->Ci)
flatten_volume_closure_tree(sd, globals->Ci);
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index 0f8542b0546..045abdb80af 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -29,6 +29,8 @@ set(SRC_OSL
node_glossy_bsdf.osl
node_gradient_texture.osl
node_hair_info.osl
+ node_scatter_volume.osl
+ node_absorption_volume.osl
node_holdout.osl
node_hsv.osl
node_image_texture.osl
diff --git a/intern/cycles/kernel/shaders/node_absorption_volume.osl b/intern/cycles/kernel/shaders/node_absorption_volume.osl
new file mode 100644
index 00000000000..69c4c0ef7af
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_absorption_volume.osl
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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
+ * limitations under the License
+ */
+
+#include "stdosl.h"
+
+shader node_absorption_volume(
+ color Color = color(0.8, 0.8, 0.8),
+ float Density = 1.0,
+ output closure color Volume = 0)
+{
+ Volume = ((color(1.0, 1.0, 1.0) - Color) * Density) * absorption();
+}
+
diff --git a/intern/cycles/kernel/shaders/node_light_path.osl b/intern/cycles/kernel/shaders/node_light_path.osl
index db5c95be079..599c7f5a262 100644
--- a/intern/cycles/kernel/shaders/node_light_path.osl
+++ b/intern/cycles/kernel/shaders/node_light_path.osl
@@ -24,6 +24,7 @@ shader node_light_path(
output float IsSingularRay = 0.0,
output float IsReflectionRay = 0.0,
output float IsTransmissionRay = 0.0,
+ output float IsVolumeScatterRay = 0.0,
output float RayLength = 0.0,
output float RayDepth = 0.0)
{
@@ -34,6 +35,7 @@ shader node_light_path(
IsSingularRay = raytype("singular");
IsReflectionRay = raytype("reflection");
IsTransmissionRay = raytype("refraction");
+ IsVolumeScatterRay = raytype("volume_scatter");
getattribute("path:ray_length", RayLength);
diff --git a/intern/cycles/kernel/shaders/node_scatter_volume.osl b/intern/cycles/kernel/shaders/node_scatter_volume.osl
new file mode 100644
index 00000000000..bf23abbf933
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_scatter_volume.osl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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
+ * limitations under the License
+ */
+
+#include "stdosl.h"
+
+shader node_scatter_volume(
+ color Color = color(0.8, 0.8, 0.8),
+ float Density = 1.0,
+ float Anisotropy = 0.0,
+ output closure color Volume = 0)
+{
+ Volume = (Color * Density) * henyey_greenstein(Anisotropy);
+}
+
diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h
index d1d1222af44..6f824ea8ebd 100644
--- a/intern/cycles/kernel/shaders/stdosl.h
+++ b/intern/cycles/kernel/shaders/stdosl.h
@@ -497,9 +497,14 @@ closure color ambient_occlusion() BUILTIN;
closure color bssrdf_cubic(normal N, vector radius, float texture_blur, float sharpness) BUILTIN;
closure color bssrdf_gaussian(normal N, vector radius, float texture_blur) BUILTIN;
+// Hair
closure color hair_reflection(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN;
closure color hair_transmission(normal N, float roughnessu, float roughnessv, vector T, float offset) BUILTIN;
+// Volume
+closure color henyey_greenstein(float g) BUILTIN;
+closure color absorption() BUILTIN;
+
// Backwards compatibility
closure color bssrdf_cubic(normal N, vector radius) BUILTIN;
closure color bssrdf_gaussian(normal N, vector radius) BUILTIN;
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
index 2c6fb5deca4..dca9c3a91e5 100644
--- a/intern/cycles/kernel/svm/svm_closure.h
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -77,7 +77,7 @@ ccl_device_inline ShaderClosure *svm_node_closure_get_bsdf(ShaderData *sd, float
float3 weight = sc->weight * mix_weight;
float sample_weight = fabsf(average(weight));
- if(sample_weight > 1e-5f && sd->num_closure < MAX_CLOSURE) {
+ if(sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) {
sc->weight = weight;
sc->sample_weight = sample_weight;
sd->num_closure++;
@@ -390,7 +390,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float *
if(path_flag & PATH_RAY_DIFFUSE_ANCESTOR)
param1 = 0.0f;
- if(sample_weight > 1e-5f && sd->num_closure+2 < MAX_CLOSURE) {
+ if(sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure+2 < MAX_CLOSURE) {
/* radius * scale */
float3 radius = stack_load_float3(stack, data_node.z)*param1;
/* sharpness */
@@ -473,24 +473,25 @@ ccl_device void svm_node_closure_volume(KernelGlobals *kg, ShaderData *sd, float
#endif
float param1 = (stack_valid(param1_offset))? stack_load_float(stack, param1_offset): __uint_as_float(node.z);
- //float param2 = (stack_valid(param2_offset))? stack_load_float(stack, param2_offset): __uint_as_float(node.w);
+ float param2 = (stack_valid(param2_offset))? stack_load_float(stack, param2_offset): __uint_as_float(node.w);
+ float density = param1;
switch(type) {
- case CLOSURE_VOLUME_TRANSPARENT_ID: {
- ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
+ case CLOSURE_VOLUME_ABSORPTION_ID: {
+ ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight * density);
if(sc) {
- float density = param1;
- sd->flag |= volume_transparent_setup(sc, density);
+ sd->flag |= volume_absorption_setup(sc);
}
break;
}
- case CLOSURE_VOLUME_ISOTROPIC_ID: {
- ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight);
+ case CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID: {
+ ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight * density);
if(sc) {
- float density = param1;
- sd->flag |= volume_isotropic_setup(sc, density);
+ float g = param2;
+ sc->data0 = g;
+ sd->flag |= volume_henyey_greenstein_setup(sc);
}
break;
}
diff --git a/intern/cycles/kernel/svm/svm_light_path.h b/intern/cycles/kernel/svm/svm_light_path.h
index e7afa2d2200..8968146c5e2 100644
--- a/intern/cycles/kernel/svm/svm_light_path.h
+++ b/intern/cycles/kernel/svm/svm_light_path.h
@@ -30,6 +30,7 @@ ccl_device void svm_node_light_path(ShaderData *sd, float *stack, uint type, uin
case NODE_LP_singular: info = (path_flag & PATH_RAY_SINGULAR)? 1.0f: 0.0f; break;
case NODE_LP_reflection: info = (path_flag & PATH_RAY_REFLECT)? 1.0f: 0.0f; break;
case NODE_LP_transmission: info = (path_flag & PATH_RAY_TRANSMIT)? 1.0f: 0.0f; break;
+ case NODE_LP_volume_scatter: info = (path_flag & PATH_RAY_VOLUME_SCATTER)? 1.0f: 0.0f; break;
case NODE_LP_backfacing: info = (sd->flag & SD_BACKFACING)? 1.0f: 0.0f; break;
case NODE_LP_ray_length: info = sd->ray_length; break;
case NODE_LP_ray_depth: info = (float)sd->ray_depth; break;
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index abd63530d63..e6df5fe17b7 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -154,6 +154,7 @@ typedef enum NodeLightPath {
NODE_LP_singular,
NODE_LP_reflection,
NODE_LP_transmission,
+ NODE_LP_volume_scatter,
NODE_LP_backfacing,
NODE_LP_ray_length,
NODE_LP_ray_depth
@@ -389,8 +390,8 @@ typedef enum ClosureType {
/* Volume */
CLOSURE_VOLUME_ID,
- CLOSURE_VOLUME_TRANSPARENT_ID,
- CLOSURE_VOLUME_ISOTROPIC_ID,
+ CLOSURE_VOLUME_ABSORPTION_ID,
+ CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID,
NBUILTIN_CLOSURES
} ClosureType;
@@ -402,12 +403,14 @@ typedef enum ClosureType {
#define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSMISSION_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID)
#define CLOSURE_IS_BSDF_BSSRDF(type) (type == CLOSURE_BSDF_BSSRDF_ID)
#define CLOSURE_IS_BSSRDF(type) (type >= CLOSURE_BSSRDF_CUBIC_ID && type <= CLOSURE_BSSRDF_GAUSSIAN_ID)
-#define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_ISOTROPIC_ID)
+#define CLOSURE_IS_VOLUME(type) (type >= CLOSURE_VOLUME_ID && type <= CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID)
#define CLOSURE_IS_EMISSION(type) (type == CLOSURE_EMISSION_ID)
#define CLOSURE_IS_HOLDOUT(type) (type == CLOSURE_HOLDOUT_ID)
#define CLOSURE_IS_BACKGROUND(type) (type == CLOSURE_BACKGROUND_ID)
#define CLOSURE_IS_AMBIENT_OCCLUSION(type) (type == CLOSURE_AMBIENT_OCCLUSION_ID)
+#define CLOSURE_WEIGHT_CUTOFF 1e-5f
+
CCL_NAMESPACE_END
#endif /* __SVM_TYPES_H__ */
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index c26ff7e7306..d7988656952 100644
--- a/intern/cycles/render/nodes.cpp
+++ b/intern/cycles/render/nodes.cpp
@@ -1951,7 +1951,7 @@ void AmbientOcclusionNode::compile(OSLCompiler& compiler)
VolumeNode::VolumeNode()
: ShaderNode("volume")
{
- closure = CLOSURE_VOLUME_ISOTROPIC_ID;
+ closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f));
add_input("Density", SHADER_SOCKET_FLOAT, 1.0f);
@@ -1995,38 +1995,40 @@ void VolumeNode::compile(OSLCompiler& compiler)
assert(0);
}
-/* Transparent Volume Closure */
+/* Absorption Volume Closure */
-TransparentVolumeNode::TransparentVolumeNode()
+AbsorptionVolumeNode::AbsorptionVolumeNode()
{
- closure = CLOSURE_VOLUME_TRANSPARENT_ID;
+ closure = CLOSURE_VOLUME_ABSORPTION_ID;
}
-void TransparentVolumeNode::compile(SVMCompiler& compiler)
+void AbsorptionVolumeNode::compile(SVMCompiler& compiler)
{
VolumeNode::compile(compiler, input("Density"), NULL);
}
-void TransparentVolumeNode::compile(OSLCompiler& compiler)
+void AbsorptionVolumeNode::compile(OSLCompiler& compiler)
{
- compiler.add(this, "node_transparent_volume");
+ compiler.add(this, "node_absorption_volume");
}
-/* Isotropic Volume Closure */
+/* Scatter Volume Closure */
-IsotropicVolumeNode::IsotropicVolumeNode()
+ScatterVolumeNode::ScatterVolumeNode()
{
- closure = CLOSURE_VOLUME_ISOTROPIC_ID;
+ closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
+
+ add_input("Anisotropy", SHADER_SOCKET_FLOAT, 0.0f);
}
-void IsotropicVolumeNode::compile(SVMCompiler& compiler)
+void ScatterVolumeNode::compile(SVMCompiler& compiler)
{
- VolumeNode::compile(compiler, input("Density"), NULL);
+ VolumeNode::compile(compiler, input("Density"), input("Anisotropy"));
}
-void IsotropicVolumeNode::compile(OSLCompiler& compiler)
+void ScatterVolumeNode::compile(OSLCompiler& compiler)
{
- compiler.add(this, "node_isotropic_volume");
+ compiler.add(this, "node_scatter_volume");
}
/* Hair BSDF Closure */
@@ -2304,6 +2306,7 @@ LightPathNode::LightPathNode()
add_output("Is Singular Ray", SHADER_SOCKET_FLOAT);
add_output("Is Reflection Ray", SHADER_SOCKET_FLOAT);
add_output("Is Transmission Ray", SHADER_SOCKET_FLOAT);
+ add_output("Is Volume Scatter Ray", SHADER_SOCKET_FLOAT);
add_output("Ray Length", SHADER_SOCKET_FLOAT);
add_output("Ray Depth", SHADER_SOCKET_FLOAT);
}
@@ -2355,6 +2358,12 @@ void LightPathNode::compile(SVMCompiler& compiler)
compiler.add_node(NODE_LIGHT_PATH, NODE_LP_transmission, out->stack_offset);
}
+ out = output("Is Volume Scatter Ray");
+ if(!out->links.empty()) {
+ compiler.stack_assign(out);
+ compiler.add_node(NODE_LIGHT_PATH, NODE_LP_volume_scatter, out->stack_offset);
+ }
+
out = output("Ray Length");
if(!out->links.empty()) {
compiler.stack_assign(out);
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index d7a110af83b..36348044bbc 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -316,14 +316,14 @@ public:
ClosureType closure;
};
-class TransparentVolumeNode : public VolumeNode {
+class AbsorptionVolumeNode : public VolumeNode {
public:
- SHADER_NODE_CLASS(TransparentVolumeNode)
+ SHADER_NODE_CLASS(AbsorptionVolumeNode)
};
-class IsotropicVolumeNode : public VolumeNode {
+class ScatterVolumeNode : public VolumeNode {
public:
- SHADER_NODE_CLASS(IsotropicVolumeNode)
+ SHADER_NODE_CLASS(ScatterVolumeNode)
};
class HairBsdfNode : public BsdfNode {
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 4ed8ece0556..043d8d138f6 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -195,15 +195,16 @@ void OSLShaderManager::shading_system_init()
/* our own ray types */
static const char *raytypes[] = {
- "camera", /* PATH_RAY_CAMERA */
- "reflection", /* PATH_RAY_REFLECT */
- "refraction", /* PATH_RAY_TRANSMIT */
- "diffuse", /* PATH_RAY_DIFFUSE */
- "glossy", /* PATH_RAY_GLOSSY */
- "singular", /* PATH_RAY_SINGULAR */
- "transparent", /* PATH_RAY_TRANSPARENT */
- "shadow", /* PATH_RAY_SHADOW_OPAQUE */
- "shadow", /* PATH_RAY_SHADOW_TRANSPARENT */
+ "camera", /* PATH_RAY_CAMERA */
+ "reflection", /* PATH_RAY_REFLECT */
+ "refraction", /* PATH_RAY_TRANSMIT */
+ "diffuse", /* PATH_RAY_DIFFUSE */
+ "glossy", /* PATH_RAY_GLOSSY */
+ "singular", /* PATH_RAY_SINGULAR */
+ "transparent", /* PATH_RAY_TRANSPARENT */
+ "volume_scatter", /* PATH_RAY_VOLUME_SCATTER */
+ "shadow", /* PATH_RAY_SHADOW_OPAQUE */
+ "shadow", /* PATH_RAY_SHADOW_TRANSPARENT */
"__unused__",
"__unused__",