diff options
Diffstat (limited to 'intern/cycles/render')
-rw-r--r-- | intern/cycles/render/attribute.cpp | 5 | ||||
-rw-r--r-- | intern/cycles/render/geometry.cpp | 59 | ||||
-rw-r--r-- | intern/cycles/render/hair.cpp | 115 | ||||
-rw-r--r-- | intern/cycles/render/hair.h | 4 |
4 files changed, 163 insertions, 20 deletions
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index aaf21ad9fd2..d7e6939cd80 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -366,6 +366,8 @@ const char *Attribute::standard_name(AttributeStandard std) return "pointiness"; case ATTR_STD_RANDOM_PER_ISLAND: return "random_per_island"; + case ATTR_STD_SHADOW_TRANSPARENCY: + return "shadow_transparency"; case ATTR_STD_NOT_FOUND: case ATTR_STD_NONE: case ATTR_STD_NUM: @@ -603,6 +605,9 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) case ATTR_STD_RANDOM_PER_ISLAND: attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_FACE); break; + case ATTR_STD_SHADOW_TRANSPARENCY: + attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY); + break; default: assert(0); break; diff --git a/intern/cycles/render/geometry.cpp b/intern/cycles/render/geometry.cpp index 5d89060c1a1..5cedab24ceb 100644 --- a/intern/cycles/render/geometry.cpp +++ b/intern/cycles/render/geometry.cpp @@ -734,6 +734,10 @@ void GeometryManager::device_update_attributes(Device *device, Shader *shader = static_cast<Shader *>(node); geom_attributes[i].add(shader->attributes); } + + if (geom->is_hair() && static_cast<Hair *>(geom)->need_shadow_transparency()) { + geom_attributes[i].add(ATTR_STD_SHADOW_TRANSPARENCY); + } } /* convert object attributes to use the same data structures as geometry ones */ @@ -1659,6 +1663,7 @@ void GeometryManager::device_update(Device *device, VLOG(1) << "Total " << scene->geometry.size() << " meshes."; bool true_displacement_used = false; + bool curve_shadow_transparency_used = false; size_t total_tess_needed = 0; { @@ -1669,26 +1674,33 @@ void GeometryManager::device_update(Device *device, }); foreach (Geometry *geom, scene->geometry) { - if (geom->is_modified() && - (geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME)) { - Mesh *mesh = static_cast<Mesh *>(geom); + if (geom->is_modified()) { + if ((geom->geometry_type == Geometry::MESH || geom->geometry_type == Geometry::VOLUME)) { + Mesh *mesh = static_cast<Mesh *>(geom); - /* Update normals. */ - mesh->add_face_normals(); - mesh->add_vertex_normals(); + /* Update normals. */ + mesh->add_face_normals(); + mesh->add_vertex_normals(); - if (mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) { - mesh->add_undisplaced(); - } + if (mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) { + mesh->add_undisplaced(); + } - /* Test if we need tessellation. */ - if (mesh->need_tesselation()) { - total_tess_needed++; - } + /* Test if we need tessellation. */ + if (mesh->need_tesselation()) { + total_tess_needed++; + } - /* Test if we need displacement. */ - if (mesh->has_true_displacement()) { - true_displacement_used = true; + /* Test if we need displacement. */ + if (mesh->has_true_displacement()) { + true_displacement_used = true; + } + } + else if (geom->geometry_type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + if (hair->need_shadow_transparency()) { + curve_shadow_transparency_used = true; + } } if (progress.get_cancel()) { @@ -1752,7 +1764,7 @@ void GeometryManager::device_update(Device *device, /* Update images needed for true displacement. */ bool old_need_object_flags_update = false; - if (true_displacement_used) { + if (true_displacement_used || curve_shadow_transparency_used) { scoped_callback_timer timer([scene](double time) { if (scene->update_stats) { scene->update_stats->geometry.times.add_entry( @@ -1770,7 +1782,7 @@ void GeometryManager::device_update(Device *device, const BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout, device->get_bvh_layout_mask()); mesh_calc_offset(scene, bvh_layout); - if (true_displacement_used) { + if (true_displacement_used || curve_shadow_transparency_used) { scoped_callback_timer timer([scene](double time) { if (scene->update_stats) { scene->update_stats->geometry.times.add_entry( @@ -1795,8 +1807,9 @@ void GeometryManager::device_update(Device *device, } } - /* Update displacement. */ + /* Update displacement and hair shadow transparency. */ bool displacement_done = false; + bool curve_shadow_transparency_done = false; size_t num_bvh = 0; { @@ -1817,6 +1830,12 @@ void GeometryManager::device_update(Device *device, displacement_done = true; } } + else if (geom->geometry_type == Geometry::HAIR) { + Hair *hair = static_cast<Hair *>(geom); + if (hair->update_shadow_transparency(device, scene, progress)) { + curve_shadow_transparency_done = true; + } + } } if (geom->is_modified() || geom->need_update_bvh_for_offset) { @@ -1836,7 +1855,7 @@ void GeometryManager::device_update(Device *device, } /* Device re-update after displacement. */ - if (displacement_done) { + if (displacement_done || curve_shadow_transparency_done) { scoped_callback_timer timer([scene](double time) { if (scene->update_stats) { scene->update_stats->geometry.times.add_entry( diff --git a/intern/cycles/render/hair.cpp b/intern/cycles/render/hair.cpp index e757e3fd3e0..4656148119a 100644 --- a/intern/cycles/render/hair.cpp +++ b/intern/cycles/render/hair.cpp @@ -18,8 +18,13 @@ #include "render/curves.h" #include "render/hair.h" +#include "render/object.h" #include "render/scene.h" +#include "integrator/shader_eval.h" + +#include "util/util_progress.h" + CCL_NAMESPACE_BEGIN /* Hair Curve */ @@ -514,4 +519,114 @@ PrimitiveType Hair::primitive_type() const ((curve_shape == CURVE_RIBBON) ? PRIMITIVE_CURVE_RIBBON : PRIMITIVE_CURVE_THICK); } +/* Fill in coordinates for curve transparency shader evaluation on device. */ +static int fill_shader_input(const Hair *hair, + const int object_index, + device_vector<KernelShaderEvalInput> &d_input) +{ + int d_input_size = 0; + KernelShaderEvalInput *d_input_data = d_input.data(); + + const int num_curves = hair->num_curves(); + for (int i = 0; i < num_curves; i++) { + const Hair::Curve curve = hair->get_curve(i); + const int num_segments = curve.num_segments(); + + for (int j = 0; j < num_segments + 1; j++) { + KernelShaderEvalInput in; + in.object = object_index; + in.prim = hair->prim_offset + i; + in.u = (j < num_segments) ? 0.0f : 1.0f; + in.v = (j < num_segments) ? __int_as_float(j) : __int_as_float(j - 1); + d_input_data[d_input_size++] = in; + } + } + + return d_input_size; +} + +/* Read back curve transparency shader output. */ +static void read_shader_output(float *shadow_transparency, + bool &is_fully_opaque, + const device_vector<float> &d_output) +{ + const int num_keys = d_output.size(); + const float *output_data = d_output.data(); + bool is_opaque = true; + + for (int i = 0; i < num_keys; i++) { + shadow_transparency[i] = output_data[i]; + if (shadow_transparency[i] > 0.0f) { + is_opaque = false; + } + } + + is_fully_opaque = is_opaque; +} + +bool Hair::need_shadow_transparency() +{ + for (const Node *node : used_shaders) { + const Shader *shader = static_cast<const Shader *>(node); + if (shader->has_surface_transparent && shader->get_use_transparent_shadow()) { + return true; + } + } + + return false; +} + +bool Hair::update_shadow_transparency(Device *device, Scene *scene, Progress &progress) +{ + if (!need_shadow_transparency()) { + /* If no shaders with shadow transparency, remove attribute. */ + Attribute *attr = attributes.find(ATTR_STD_SHADOW_TRANSPARENCY); + if (attr) { + attributes.remove(attr); + return true; + } + else { + return false; + } + } + + string msg = string_printf("Computing Shadow Transparency %s", name.c_str()); + progress.set_status("Updating Hair", msg); + + /* Create shadow transparency attribute. */ + Attribute *attr = attributes.find(ATTR_STD_SHADOW_TRANSPARENCY); + const bool attribute_exists = (attr != nullptr); + if (!attribute_exists) { + attr = attributes.add(ATTR_STD_SHADOW_TRANSPARENCY); + } + + float *attr_data = attr->data_float(); + + /* Find object index. */ + size_t object_index = OBJECT_NONE; + + for (size_t i = 0; i < scene->objects.size(); i++) { + if (scene->objects[i]->get_geometry() == this) { + object_index = i; + break; + } + } + + /* Evaluate shader on device. */ + ShaderEval shader_eval(device, progress); + bool is_fully_opaque = false; + shader_eval.eval(SHADER_EVAL_CURVE_SHADOW_TRANSPARENCY, + num_keys(), + 1, + function_bind(&fill_shader_input, this, object_index, _1), + function_bind(&read_shader_output, attr_data, is_fully_opaque, _1)); + + if (is_fully_opaque) { + attributes.remove(attr); + return attribute_exists; + } + + return true; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/hair.h b/intern/cycles/render/hair.h index 920e9601b35..3e91fc3dcbb 100644 --- a/intern/cycles/render/hair.h +++ b/intern/cycles/render/hair.h @@ -153,6 +153,10 @@ class Hair : public Geometry { KernelCurveSegment *curve_segments); PrimitiveType primitive_type() const override; + + /* Attributes */ + bool need_shadow_transparency(); + bool update_shadow_transparency(Device *device, Scene *scene, Progress &progress); }; CCL_NAMESPACE_END |