diff options
Diffstat (limited to 'intern/cycles')
70 files changed, 1858 insertions, 568 deletions
diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index 0740aa51039..00ac8e7e182 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -224,31 +224,6 @@ endif() # TODO(sergey): Consider removing it, only causes confusion in interface. set(WITH_CYCLES_DEVICE_MULTI TRUE) -if(CYCLES_STANDALONE_REPOSITORY) - TEST_UNORDERED_MAP_SUPPORT() -endif() -if(WITH_CXX11) - add_definitions(-DCYCLES_STD_UNORDERED_MAP) -elseif(HAVE_STD_UNORDERED_MAP_HEADER) - if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE) - add_definitions(-DCYCLES_STD_UNORDERED_MAP) - else() - if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE) - add_definitions(-DCYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) - else() - add_definitions(-DCYCLES_NO_UNORDERED_MAP) - message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)") - endif() - endif() -else() - if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE) - add_definitions(-DCYCLES_TR1_UNORDERED_MAP) - else() - add_definitions(-DCYCLES_NO_UNORDERED_MAP) - message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)") - endif() -endif() - # Logging capabilities using GLog library. if(WITH_CYCLES_LOGGING) add_definitions(-DWITH_CYCLES_LOGGING) diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index 5c52a8bcce9..476cf975737 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -52,7 +52,9 @@ def _workaround_buggy_drivers(): def _configure_argument_parser(): import argparse - parser = argparse.ArgumentParser(description="Cycles Addon argument parser") + # No help because it conflicts with general Python scripts argument parsing + parser = argparse.ArgumentParser(description="Cycles Addon argument parser", + add_help=False) parser.add_argument("--cycles-resumable-num-chunks", help="Number of chunks to split sample range into", default=None) @@ -65,6 +67,9 @@ def _configure_argument_parser(): parser.add_argument("--cycles-resumable-end-chunk", help="End chunk to render", default=None) + parser.add_argument("--cycles-print-stats", + help="Print rendering statistics to stderr", + action='store_true') return parser @@ -93,6 +98,9 @@ def _parse_command_line(): int(args.cycles_resumable_start_chunk), int(args.cycles_resumable_end_chunk), ) + if args.cycles_print_stats: + import _cycles + _cycles.enable_print_stats() def init(): @@ -168,7 +176,7 @@ def reset(engine, data, depsgraph): import bpy if bpy.app.debug_value == 256: - _cycles.debug_flags_update(depsgraph.scene) + _cycles.debug_flags_update(depsgraph.scene.as_pointer()) else: _cycles.debug_flags_reset() diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 6e56e42f9b2..737f7416486 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -883,14 +883,9 @@ class CYCLES_CAMERA_PT_dof_viewport(CyclesButtonsPanel, Panel): cam = context.camera dof_options = cam.gpu_dof - hq_support = dof_options.is_hq_supported sub = flow.column(align=True) - subhq = sub.column() - subhq.active = hq_support - subhq.prop(dof_options, "use_high_quality") sub.prop(dof_options, "fstop") - if dof_options.use_high_quality and hq_support: - sub.prop(dof_options, "blades") + sub.prop(dof_options, "blades") class CYCLES_PT_context_material(CyclesButtonsPanel, Panel): @@ -900,7 +895,10 @@ class CYCLES_PT_context_material(CyclesButtonsPanel, Panel): @classmethod def poll(cls, context): - return (context.material or context.object) and CyclesButtonsPanel.poll(context) + if context.active_object and context.active_object.type == 'GPENCIL': + return False + else: + return (context.material or context.object) and CyclesButtonsPanel.poll(context) def draw(self, context): layout = self.layout @@ -1227,7 +1225,7 @@ class CYCLES_WORLD_PT_surface(CyclesButtonsPanel, Panel): world = context.world if not panel_node_draw(layout, world, 'OUTPUT_WORLD', 'Surface'): - layout.prop(world, "horizon_color", text="Color") + layout.prop(world, "color") class CYCLES_WORLD_PT_volume(CyclesButtonsPanel, Panel): diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index c7e8fb6f72f..1d0e8fc6ace 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -1077,38 +1077,21 @@ Mesh *BlenderSync::sync_mesh(BL::Depsgraph& b_depsgraph, bool object_updated, bool hide_tris) { - /* When viewport display is not needed during render we can force some - * caches to be releases from blender side in order to reduce peak memory - * footprint during synchronization process. - */ - const bool is_interface_locked = b_engine.render() && - b_engine.render().use_lock_interface(); - const bool can_free_caches = BlenderSession::headless || is_interface_locked; - /* test if we can instance or if the object is modified */ BL::ID b_ob_data = b_ob.data(); BL::ID key = (BKE_object_is_modified(b_ob))? b_ob_instance: b_ob_data; - BL::Material material_override = view_layer.material_override; /* find shader indices */ vector<Shader*> used_shaders; BL::Object::material_slots_iterator slot; for(b_ob.material_slots.begin(slot); slot != b_ob.material_slots.end(); ++slot) { - if(material_override) { - find_shader(material_override, used_shaders, scene->default_surface); - } - else { - BL::ID b_material(slot->material()); - find_shader(b_material, used_shaders, scene->default_surface); - } + BL::ID b_material(slot->material()); + find_shader(b_material, used_shaders, scene->default_surface); } if(used_shaders.size() == 0) { - if(material_override) - find_shader(material_override, used_shaders, scene->default_surface); - else - used_shaders.push_back(scene->default_surface); + used_shaders.push_back(scene->default_surface); } /* test if we need to sync */ @@ -1210,10 +1193,6 @@ Mesh *BlenderSync::sync_mesh(BL::Depsgraph& b_depsgraph, if(view_layer.use_hair && mesh->subdivision_type == Mesh::SUBDIVISION_NONE) sync_curves(mesh, b_mesh, b_ob, false); - if(can_free_caches) { - b_ob.cache_release(); - } - if(b_mesh) { /* free derived mesh */ b_data.meshes.remove(b_mesh, false, true, false); diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index ed01d728931..a1f39d0848f 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -291,8 +291,8 @@ void BlenderSync::sync_background_light(bool use_portal) /* Object */ Object *BlenderSync::sync_object(BL::Depsgraph& b_depsgraph, + BL::ViewLayer& b_view_layer, BL::DepsgraphObjectInstance& b_instance, - uint layer_flag, float motion_time, bool hide_tris, BlenderObjectCulling& culling, @@ -314,10 +314,13 @@ Object *BlenderSync::sync_object(BL::Depsgraph& b_depsgraph, } /* light is handled separately */ - if(object_is_light(b_ob)) { - /* don't use lights for excluded layers used as mask layer */ - if(!motion && !((layer_flag & view_layer.holdout_layer) && - (layer_flag & view_layer.exclude_layer))) + if(!motion && object_is_light(b_ob)) { + /* TODO: don't use lights for excluded layers used as mask layer, + * when dynamic overrides are back. */ +#if 0 + if(!((layer_flag & view_layer.holdout_layer) && + (layer_flag & view_layer.exclude_layer))) +#endif { sync_light(b_parent, persistent_id, @@ -343,21 +346,24 @@ Object *BlenderSync::sync_object(BL::Depsgraph& b_depsgraph, /* Visibility flags for both parent and child. */ PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); - bool use_holdout = (layer_flag & view_layer.holdout_layer) != 0 || - get_boolean(cobject, "is_holdout"); + bool use_holdout = get_boolean(cobject, "is_holdout") || + b_parent.holdout_get(b_view_layer); uint visibility = object_ray_visibility(b_ob) & PATH_RAY_ALL_VISIBILITY; if(b_parent.ptr.data != b_ob.ptr.data) { visibility &= object_ray_visibility(b_parent); } - /* Make holdout objects on excluded layer invisible for non-camera rays. */ + /* TODO: make holdout objects on excluded layer invisible for non-camera rays. */ +#if 0 if(use_holdout && (layer_flag & view_layer.exclude_layer)) { visibility &= ~(PATH_RAY_ALL_VISIBILITY - PATH_RAY_CAMERA); } +#endif - /* Hide objects not on render layer from camera rays. */ - if(!(layer_flag & view_layer.layer)) { + /* Clear camera visibility for indirect only objects. */ + bool use_indirect_only = b_parent.indirect_only_get(b_view_layer); + if(use_indirect_only) { visibility &= ~PATH_RAY_CAMERA; } @@ -583,6 +589,7 @@ void BlenderSync::sync_objects(BL::Depsgraph& b_depsgraph, float motion_time) bool cancel = false; bool use_portal = false; + BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); BL::Depsgraph::mode_enum depsgraph_mode = b_depsgraph.mode(); BL::Depsgraph::object_instances_iterator b_instance_iter; @@ -604,8 +611,8 @@ void BlenderSync::sync_objects(BL::Depsgraph& b_depsgraph, float motion_time) if(!object_render_hide(b_ob, true, true, hide_tris, depsgraph_mode)) { /* object itself */ sync_object(b_depsgraph, + b_view_layer, b_instance, - ~(0), /* until we get rid of layers */ motion_time, hide_tris, culling, diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 4c199f4838f..a79c28e43aa 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -738,6 +738,12 @@ static PyObject *set_resumable_chunk_range_func(PyObject * /*self*/, PyObject *a Py_RETURN_NONE; } +static PyObject *enable_print_stats_func(PyObject * /*self*/, PyObject * /*args*/) +{ + BlenderSession::print_render_stats = true; + Py_RETURN_NONE; +} + static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/) { vector<DeviceInfo>& devices = Device::available_devices(); @@ -776,6 +782,9 @@ static PyMethodDef methods[] = { {"debug_flags_update", debug_flags_update_func, METH_VARARGS, ""}, {"debug_flags_reset", debug_flags_reset_func, METH_NOARGS, ""}, + /* Statistics. */ + {"enable_print_stats", enable_print_stats_func, METH_NOARGS, ""}, + /* Resumable render */ {"set_resumable_chunk", set_resumable_chunk_func, METH_VARARGS, ""}, {"set_resumable_chunk_range", set_resumable_chunk_range_func, METH_VARARGS, ""}, diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index cd55155e33b..05adb6f5fe0 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -28,6 +28,7 @@ #include "render/scene.h" #include "render/session.h" #include "render/shader.h" +#include "render/stats.h" #include "util/util_color.h" #include "util/util_foreach.h" @@ -48,6 +49,7 @@ int BlenderSession::num_resumable_chunks = 0; int BlenderSession::current_resumable_chunk = 0; int BlenderSession::start_resumable_chunk = 0; int BlenderSession::end_resumable_chunk = 0; +bool BlenderSession::print_render_stats = false; BlenderSession::BlenderSession(BL::RenderEngine& b_engine, BL::UserPreferences& b_userpref, @@ -461,15 +463,13 @@ void BlenderSession::render(BL::Depsgraph& b_depsgraph_) scene->integrator->tag_update(scene); } - /* Update number of samples per layer. */ - int samples = sync->get_layer_samples(); - bool bound_samples = sync->get_layer_bound_samples(); - int effective_layer_samples; + int effective_layer_samples = session_params.samples; + /* TODO: Update number of samples per layer. */ +#if 0 if(samples != 0 && (!bound_samples || (samples < session_params.samples))) effective_layer_samples = samples; - else - effective_layer_samples = session_params.samples; +#endif /* Update tile manager if we're doing resumable render. */ update_resumable_tile_manager(effective_layer_samples); @@ -481,6 +481,12 @@ void BlenderSession::render(BL::Depsgraph& b_depsgraph_) session->start(); session->wait(); + if(!b_engine.is_preview() && background && print_render_stats) { + RenderStats stats; + session->scene->collect_statistics(&stats); + printf("Render statistics:\n%s\n", stats.full_report().c_str()); + } + if(session->progress.get_cancel()) break; } diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index 1d727e416a0..2be57f293b4 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -145,6 +145,8 @@ public: static int start_resumable_chunk; static int end_resumable_chunk; + static bool print_render_stats; + protected: void do_write_update_render_result(BL::RenderResult& b_rr, BL::RenderLayer& b_rlay, diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 6129565fec5..62c160ca503 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -517,6 +517,12 @@ static ShaderNode *add_node(Scene *scene, } node = hair; } + else if(b_node.is_a(&RNA_ShaderNodeBsdfHairPrincipled)) { + BL::ShaderNodeBsdfHairPrincipled b_principled_hair_node(b_node); + PrincipledHairBsdfNode *principled_hair = new PrincipledHairBsdfNode(); + principled_hair->parametrization = (NodePrincipledHairParametrization) get_enum(b_principled_hair_node.ptr, "parametrization", NODE_PRINCIPLED_HAIR_NUM, NODE_PRINCIPLED_HAIR_REFLECTANCE); + node = principled_hair; + } else if(b_node.is_a(&RNA_ShaderNodeBsdfPrincipled)) { BL::ShaderNodeBsdfPrincipled b_principled_node(b_node); PrincipledBsdfNode *principled = new PrincipledBsdfNode(); @@ -1330,7 +1336,7 @@ void BlenderSync::sync_world(BL::Depsgraph& b_depsgraph, bool update_all) } else if(b_world) { BackgroundNode *background = new BackgroundNode(); - background->color = get_float3(b_world.horizon_color()); + background->color = get_float3(b_world.color()); graph->add(background); ShaderNode *out = graph->output(); diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index cbca623ece7..93232fbf98f 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -207,6 +207,8 @@ void BlenderSync::sync_data(BL::RenderSettings& b_render, python_thread_state); mesh_synced.clear(); + + free_data_after_sync(b_depsgraph); } /* Integrator */ @@ -363,28 +365,11 @@ void BlenderSync::sync_film() void BlenderSync::sync_view_layer(BL::SpaceView3D& /*b_v3d*/, BL::ViewLayer& b_view_layer) { /* render layer */ - uint layer_override = get_layer(b_engine.layer_override()); - uint view_layers = layer_override ? layer_override : get_layer(b_scene.layers()); - view_layer.name = b_view_layer.name(); - - view_layer.holdout_layer = 0; - view_layer.exclude_layer = 0; - - view_layer.view_layer = view_layers & ~view_layer.exclude_layer; - view_layer.view_layer |= view_layer.exclude_layer & view_layer.holdout_layer; - - view_layer.layer = (1 << 20) - 1; - view_layer.layer |= view_layer.holdout_layer; - - view_layer.material_override = PointerRNA_NULL; view_layer.use_background_shader = b_view_layer.use_sky(); view_layer.use_background_ao = b_view_layer.use_ao(); view_layer.use_surfaces = b_view_layer.use_solid(); view_layer.use_hair = b_view_layer.use_strand(); - - view_layer.bound_samples = false; - view_layer.samples = 0; } /* Images */ @@ -566,6 +551,30 @@ array<Pass> BlenderSync::sync_render_passes(BL::RenderLayer& b_rlay, return passes; } +void BlenderSync::free_data_after_sync(BL::Depsgraph& b_depsgraph) +{ + /* When viewport display is not needed during render we can force some + * caches to be releases from blender side in order to reduce peak memory + * footprint during synchronization process. + */ + const bool is_interface_locked = b_engine.render() && + b_engine.render().use_lock_interface(); + const bool can_free_caches = BlenderSession::headless || is_interface_locked; + if (!can_free_caches) { + return; + } + /* TODO(sergey): We can actually remove the whole dependency graph, + * but that will need some API support first. + */ + BL::Depsgraph::objects_iterator b_ob; + for(b_depsgraph.objects.begin(b_ob); + b_ob != b_depsgraph.objects.end(); + ++b_ob) + { + b_ob->cache_release(); + } +} + /* Scene Parameters */ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene, diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index cd1a37d3f13..e63ef9e5e47 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -78,8 +78,6 @@ public: void sync_view(BL::SpaceView3D& b_v3d, BL::RegionView3D& b_rv3d, int width, int height); - inline int get_layer_samples() { return view_layer.samples; } - inline int get_layer_bound_samples() { return view_layer.bound_samples; } /* get parameters */ static SceneParams get_scene_params(BL::Scene& b_scene, @@ -126,8 +124,8 @@ private: bool motion, int motion_step = 0); Object *sync_object(BL::Depsgraph& b_depsgraph, + BL::ViewLayer& b_view_layer, BL::DepsgraphObjectInstance& b_instance, - uint layer_flag, float motion_time, bool hide_tris, BlenderObjectCulling& culling, @@ -157,6 +155,9 @@ private: /* Images. */ void sync_images(); + /* Early data free. */ + void free_data_after_sync(BL::Depsgraph& b_depsgraph); + /* util */ void find_shader(BL::ID& id, vector<Shader*>& used_shaders, Shader *default_shader); bool BKE_object_is_modified(BL::Object& b_ob); @@ -188,28 +189,18 @@ private: struct RenderLayerInfo { RenderLayerInfo() - : view_layer(0), layer(0), - holdout_layer(0), exclude_layer(0), - material_override(PointerRNA_NULL), - use_background_shader(true), + : use_background_shader(true), use_background_ao(true), use_surfaces(true), - use_hair(true), - samples(0), bound_samples(false) + use_hair(true) {} string name; uint view_layer; - uint layer; /* This can be safely removed from Cycles. */ - uint holdout_layer; /* This can be safely removed from Cycles. */ - uint exclude_layer; /* This can be safely removed from Cycles. */ - BL::Material material_override; /* This can be safely removed from Cycles. */ bool use_background_shader; bool use_background_ao; bool use_surfaces; bool use_hair; - int samples; /* This can be safely removed from Cycles. */ - bool bound_samples; /* This can be safely removed from Cycles. */ } view_layer; Progress &progress; diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index 95eef8263d4..be0f8f45399 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -23,6 +23,7 @@ #include "util/util_foreach.h" #include "util/util_logging.h" #include "util/util_set.h" +#include "util/util_string.h" CCL_NAMESPACE_BEGIN @@ -166,11 +167,14 @@ string device_opencl_capabilities(void) platform_ids.resize(num_platforms); opencl_assert(clGetPlatformIDs(num_platforms, &platform_ids[0], NULL)); -#define APPEND_STRING_INFO(func, id, name, what) \ + typedef char cl_string[1024]; + +#define APPEND_INFO(func, id, name, what, type) \ do { \ - char data[1024] = "\0"; \ + type data; \ + memset(&data, 0, sizeof(data)); \ opencl_assert(func(id, what, sizeof(data), &data, NULL)); \ - result += string_printf("%s: %s\n", name, data); \ + result += string_printf("%s: %s\n", name, to_string(data).c_str()); \ } while(false) #define APPEND_STRING_EXTENSION_INFO(func, id, name, what) \ do { \ @@ -182,10 +186,10 @@ string device_opencl_capabilities(void) } \ } \ } while(false) -#define APPEND_PLATFORM_STRING_INFO(id, name, what) \ - APPEND_STRING_INFO(clGetPlatformInfo, id, "\tPlatform " name, what) -#define APPEND_DEVICE_STRING_INFO(id, name, what) \ - APPEND_STRING_INFO(clGetDeviceInfo, id, "\t\t\tDevice " name, what) +#define APPEND_PLATFORM_INFO(id, name, what, type) \ + APPEND_INFO(clGetPlatformInfo, id, "\tPlatform " name, what, type) +#define APPEND_DEVICE_INFO(id, name, what, type) \ + APPEND_INFO(clGetDeviceInfo, id, "\t\t\tDevice " name, what, type) #define APPEND_DEVICE_STRING_EXTENSION_INFO(id, name, what) \ APPEND_STRING_EXTENSION_INFO(clGetDeviceInfo, id, "\t\t\tDevice " name, what) @@ -195,11 +199,11 @@ string device_opencl_capabilities(void) result += string_printf("Platform #%u\n", platform); - APPEND_PLATFORM_STRING_INFO(platform_id, "Name", CL_PLATFORM_NAME); - APPEND_PLATFORM_STRING_INFO(platform_id, "Vendor", CL_PLATFORM_VENDOR); - APPEND_PLATFORM_STRING_INFO(platform_id, "Version", CL_PLATFORM_VERSION); - APPEND_PLATFORM_STRING_INFO(platform_id, "Profile", CL_PLATFORM_PROFILE); - APPEND_PLATFORM_STRING_INFO(platform_id, "Extensions", CL_PLATFORM_EXTENSIONS); + APPEND_PLATFORM_INFO(platform_id, "Name", CL_PLATFORM_NAME, cl_string); + APPEND_PLATFORM_INFO(platform_id, "Vendor", CL_PLATFORM_VENDOR, cl_string); + APPEND_PLATFORM_INFO(platform_id, "Version", CL_PLATFORM_VERSION, cl_string); + APPEND_PLATFORM_INFO(platform_id, "Profile", CL_PLATFORM_PROFILE, cl_string); + APPEND_PLATFORM_INFO(platform_id, "Extensions", CL_PLATFORM_EXTENSIONS, cl_string); cl_uint num_devices = 0; opencl_assert(clGetDeviceIDs(platform_ids[platform], @@ -220,13 +224,16 @@ string device_opencl_capabilities(void) result += string_printf("\t\tDevice: #%u\n", device); - APPEND_DEVICE_STRING_INFO(device_id, "Name", CL_DEVICE_NAME); + APPEND_DEVICE_INFO(device_id, "Name", CL_DEVICE_NAME, cl_string); APPEND_DEVICE_STRING_EXTENSION_INFO(device_id, "Board Name", CL_DEVICE_BOARD_NAME_AMD); - APPEND_DEVICE_STRING_INFO(device_id, "Vendor", CL_DEVICE_VENDOR); - APPEND_DEVICE_STRING_INFO(device_id, "OpenCL C Version", CL_DEVICE_OPENCL_C_VERSION); - APPEND_DEVICE_STRING_INFO(device_id, "Profile", CL_DEVICE_PROFILE); - APPEND_DEVICE_STRING_INFO(device_id, "Version", CL_DEVICE_VERSION); - APPEND_DEVICE_STRING_INFO(device_id, "Extensions", CL_DEVICE_EXTENSIONS); + APPEND_DEVICE_INFO(device_id, "Vendor", CL_DEVICE_VENDOR, cl_string); + APPEND_DEVICE_INFO(device_id, "OpenCL C Version", CL_DEVICE_OPENCL_C_VERSION, cl_string); + APPEND_DEVICE_INFO(device_id, "Profile", CL_DEVICE_PROFILE, cl_string); + APPEND_DEVICE_INFO(device_id, "Version", CL_DEVICE_VERSION, cl_string); + APPEND_DEVICE_INFO(device_id, "Extensions", CL_DEVICE_EXTENSIONS, cl_string); + APPEND_DEVICE_INFO(device_id, "Max clock frequency (MHz)", CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint); + APPEND_DEVICE_INFO(device_id, "Max compute units", CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint); + APPEND_DEVICE_INFO(device_id, "Max work group size", CL_DEVICE_MAX_WORK_GROUP_SIZE, size_t); } } diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp index 9104f64bedd..d6304ba688a 100644 --- a/intern/cycles/device/opencl/opencl_util.cpp +++ b/intern/cycles/device/opencl/opencl_util.cpp @@ -1136,6 +1136,21 @@ string OpenCLInfo::get_readable_device_name(cl_device_id device_id) name = get_device_name(device_id); } + /* Special exception for AMD Vega, need to be able to tell + * Vega 56 from 64 apart. + */ + if (name == "Radeon RX Vega") { + cl_int max_compute_units = 0; + if (clGetDeviceInfo(device_id, + CL_DEVICE_MAX_COMPUTE_UNITS, + sizeof(max_compute_units), + &max_compute_units, + NULL) == CL_SUCCESS) + { + name += " " + to_string(max_compute_units); + } + } + /* Distinguish from our native CPU device. */ if(get_device_type(device_id) & CL_DEVICE_TYPE_CPU) { name += " (OpenCL)"; diff --git a/intern/cycles/graph/node.cpp b/intern/cycles/graph/node.cpp index 45ffc8d7d6b..5960d9aa7d5 100644 --- a/intern/cycles/graph/node.cpp +++ b/intern/cycles/graph/node.cpp @@ -425,20 +425,22 @@ bool Node::equals(const Node& other) const /* Hash */ +namespace { + template<typename T> -static void value_hash(const Node *node, const SocketType& socket, MD5Hash& md5) +void value_hash(const Node *node, const SocketType& socket, MD5Hash& md5) { md5.append(((uint8_t*)node) + socket.struct_offset, socket.size()); } -static void float3_hash(const Node *node, const SocketType& socket, MD5Hash& md5) +void float3_hash(const Node *node, const SocketType& socket, MD5Hash& md5) { /* Don't compare 4th element used for padding. */ md5.append(((uint8_t*)node) + socket.struct_offset, sizeof(float) * 3); } template<typename T> -static void array_hash(const Node *node, const SocketType& socket, MD5Hash& md5) +void array_hash(const Node *node, const SocketType& socket, MD5Hash& md5) { const array<T>& a = *(const array<T>*)(((char*)node) + socket.struct_offset); for (size_t i = 0; i < a.size(); i++) { @@ -446,7 +448,7 @@ static void array_hash(const Node *node, const SocketType& socket, MD5Hash& md5) } } -static void float3_array_hash(const Node *node, const SocketType& socket, MD5Hash& md5) +void float3_array_hash(const Node *node, const SocketType& socket, MD5Hash& md5) { /* Don't compare 4th element used for padding. */ const array<float3>& a = *(const array<float3>*)(((char*)node) + socket.struct_offset); @@ -455,6 +457,8 @@ static void float3_array_hash(const Node *node, const SocketType& socket, MD5Has } } +} // namespace + void Node::hash(MD5Hash& md5) { md5.append(type->name.string()); @@ -495,4 +499,77 @@ void Node::hash(MD5Hash& md5) } } +namespace { + +template<typename T> +size_t array_size_in_bytes(const Node *node, const SocketType& socket) +{ + const array<T>& a = *(const array<T>*)(((char*)node) + socket.struct_offset); + return a.size() * sizeof(T); +} + +} // namespace + +size_t Node::get_total_size_in_bytes() const +{ + size_t total_size = 0; + foreach(const SocketType& socket, type->inputs) { + switch(socket.type) { + case SocketType::BOOLEAN: + case SocketType::FLOAT: + case SocketType::INT: + case SocketType::UINT: + case SocketType::COLOR: + case SocketType::VECTOR: + case SocketType::POINT: + case SocketType::NORMAL: + case SocketType::POINT2: + case SocketType::CLOSURE: + case SocketType::STRING: + case SocketType::ENUM: + case SocketType::TRANSFORM: + case SocketType::NODE: + total_size += socket.size(); + break; + + case SocketType::BOOLEAN_ARRAY: + total_size += array_size_in_bytes<bool>(this, socket); + break; + case SocketType::FLOAT_ARRAY: + total_size += array_size_in_bytes<float>(this, socket); + break; + case SocketType::INT_ARRAY: + total_size += array_size_in_bytes<int>(this, socket); + break; + case SocketType::COLOR_ARRAY: + total_size += array_size_in_bytes<float3>(this, socket); + break; + case SocketType::VECTOR_ARRAY: + total_size += array_size_in_bytes<float3>(this, socket); + break; + case SocketType::POINT_ARRAY: + total_size += array_size_in_bytes<float3>(this, socket); + break; + case SocketType::NORMAL_ARRAY: + total_size += array_size_in_bytes<float3>(this, socket); + break; + case SocketType::POINT2_ARRAY: + total_size += array_size_in_bytes<float2>(this, socket); + break; + case SocketType::STRING_ARRAY: + total_size += array_size_in_bytes<ustring>(this, socket); + break; + case SocketType::TRANSFORM_ARRAY: + total_size += array_size_in_bytes<Transform>(this, socket); + break; + case SocketType::NODE_ARRAY: + total_size += array_size_in_bytes<void*>(this, socket); + break; + + case SocketType::UNDEFINED: break; + } + } + return total_size; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/graph/node.h b/intern/cycles/graph/node.h index a738bfe197e..11695a8631d 100644 --- a/intern/cycles/graph/node.h +++ b/intern/cycles/graph/node.h @@ -92,6 +92,9 @@ struct Node /* compute hash of node and its socket values */ void hash(MD5Hash& md5); + /* Get total size of this node. */ + size_t get_total_size_in_bytes() const; + ustring name; const NodeType *type; }; diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp index 671ae2d815a..e045777e969 100644 --- a/intern/cycles/graph/node_type.cpp +++ b/intern/cycles/graph/node_type.cpp @@ -134,7 +134,7 @@ NodeType::~NodeType() void NodeType::register_input(ustring name, ustring ui_name, SocketType::Type type, int struct_offset, const void *default_value, const NodeEnum *enum_values, - const NodeType **node_type, int flags, int extra_flags) + const NodeType **node_type, int flags, int extra_flags) { SocketType socket; socket.name = name; diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h index d4e2dbceff6..1d565794b27 100644 --- a/intern/cycles/graph/node_type.h +++ b/intern/cycles/graph/node_type.h @@ -114,9 +114,9 @@ struct NodeType void register_input(ustring name, ustring ui_name, SocketType::Type type, int struct_offset, const void *default_value, - const NodeEnum *enum_values = NULL, - const NodeType **node_type = NULL, - int flags = 0, int extra_flags = 0); + const NodeEnum *enum_values = NULL, + const NodeType **node_type = NULL, + int flags = 0, int extra_flags = 0); void register_output(ustring name, ustring ui_name, SocketType::Type type); const SocketType *find_input(ustring name) const; diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 092bec08a51..c4cad17429d 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -156,6 +156,7 @@ set(SRC_CLOSURE_HEADERS closure/volume.h closure/bsdf_principled_diffuse.h closure/bsdf_principled_sheen.h + closure/bsdf_hair_principled.h ) set(SRC_SVM_HEADERS diff --git a/intern/cycles/kernel/bvh/bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h index f2379efc656..2ee29ac9c27 100644 --- a/intern/cycles/kernel/bvh/bvh_volume_all.h +++ b/intern/cycles/kernel/bvh/bvh_volume_all.h @@ -212,14 +212,16 @@ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, isect_array->t = isect_t; if(num_hits == max_hits) { #if BVH_FEATURE(BVH_INSTANCING) + if(object != OBJECT_NONE) { # if BVH_FEATURE(BVH_MOTION) - float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); + float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); # else - Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); - float t_fac = 1.0f / len(transform_direction(&itfm, dir)); + Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); + float t_fac = 1.0f / len(transform_direction(&itfm, dir)); # endif - for(int i = 0; i < num_hits_in_instance; i++) { - (isect_array-i-1)->t *= t_fac; + for(int i = 0; i < num_hits_in_instance; i++) { + (isect_array-i-1)->t *= t_fac; + } } #endif /* BVH_FEATURE(BVH_INSTANCING) */ return num_hits; @@ -257,14 +259,16 @@ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, isect_array->t = isect_t; if(num_hits == max_hits) { # if BVH_FEATURE(BVH_INSTANCING) + if(object != OBJECT_NONE) { # if BVH_FEATURE(BVH_MOTION) - float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); + float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); # else - Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); - float t_fac = 1.0f / len(transform_direction(&itfm, dir)); + Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); + float t_fac = 1.0f / len(transform_direction(&itfm, dir)); # endif - for(int i = 0; i < num_hits_in_instance; i++) { - (isect_array-i-1)->t *= t_fac; + for(int i = 0; i < num_hits_in_instance; i++) { + (isect_array-i-1)->t *= t_fac; + } } # endif /* BVH_FEATURE(BVH_INSTANCING) */ return num_hits; diff --git a/intern/cycles/kernel/bvh/qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h index ac5f58a9a51..1e454e4d36b 100644 --- a/intern/cycles/kernel/bvh/qbvh_volume_all.h +++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h @@ -279,14 +279,16 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, isect_array->t = isect_t; if(num_hits == max_hits) { #if BVH_FEATURE(BVH_INSTANCING) + if(object != OBJECT_NONE) { # if BVH_FEATURE(BVH_MOTION) - float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); + float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); # else - Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); - float t_fac = 1.0f / len(transform_direction(&itfm, dir)); + Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); + float t_fac = 1.0f / len(transform_direction(&itfm, dir)); # endif - for(int i = 0; i < num_hits_in_instance; i++) { - (isect_array-i-1)->t *= t_fac; + for(int i = 0; i < num_hits_in_instance; i++) { + (isect_array-i-1)->t *= t_fac; + } } #endif /* BVH_FEATURE(BVH_INSTANCING) */ return num_hits; @@ -317,14 +319,16 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, isect_array->t = isect_t; if(num_hits == max_hits) { # if BVH_FEATURE(BVH_INSTANCING) + if(object != OBJECT_NONE) { # if BVH_FEATURE(BVH_MOTION) - float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); + float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); # else - Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); - float t_fac = 1.0f / len(transform_direction(&itfm, dir)); + Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM); + float t_fac = 1.0f / len(transform_direction(&itfm, dir)); # endif - for(int i = 0; i < num_hits_in_instance; i++) { - (isect_array-i-1)->t *= t_fac; + for(int i = 0; i < num_hits_in_instance; i++) { + (isect_array-i-1)->t *= t_fac; + } } # endif /* BVH_FEATURE(BVH_INSTANCING) */ return num_hits; diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index f191b812f11..3a9629ea9d7 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -27,6 +27,7 @@ #include "kernel/closure/bsdf_ashikhmin_shirley.h" #include "kernel/closure/bsdf_toon.h" #include "kernel/closure/bsdf_hair.h" +#include "kernel/closure/bsdf_hair_principled.h" #include "kernel/closure/bsdf_principled_diffuse.h" #include "kernel/closure/bsdf_principled_sheen.h" #include "kernel/closure/bssrdf.h" @@ -171,6 +172,10 @@ ccl_device_inline int bsdf_sample(KernelGlobals *kg, label = bsdf_hair_transmission_sample(sc, sd->Ng, sd->I, sd->dI.dx, sd->dI.dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; + case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: + label = bsdf_principled_hair_sample(kg, sc, sd, randu, randv, + eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); + break; #ifdef __PRINCIPLED__ case CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID: case CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID: @@ -284,6 +289,9 @@ float3 bsdf_eval(KernelGlobals *kg, case CLOSURE_BSDF_GLOSSY_TOON_ID: eval = bsdf_glossy_toon_eval_reflect(sc, sd->I, omega_in, pdf); break; + case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: + eval = bsdf_principled_hair_eval(kg, sd, sc, omega_in, pdf); + break; case CLOSURE_BSDF_HAIR_REFLECTION_ID: eval = bsdf_hair_reflection_eval_reflect(sc, sd->I, omega_in, pdf); break; @@ -366,6 +374,9 @@ float3 bsdf_eval(KernelGlobals *kg, case CLOSURE_BSDF_GLOSSY_TOON_ID: eval = bsdf_glossy_toon_eval_transmit(sc, sd->I, omega_in, pdf); break; + case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: + eval = bsdf_principled_hair_eval(kg, sd, sc, omega_in, pdf); + break; case CLOSURE_BSDF_HAIR_REFLECTION_ID: eval = bsdf_hair_reflection_eval_transmit(sc, sd->I, omega_in, pdf); break; @@ -424,6 +435,9 @@ ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness) case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID: bsdf_ashikhmin_shirley_blur(sc, roughness); break; + case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: + bsdf_principled_hair_blur(sc, roughness); + break; default: break; } diff --git a/intern/cycles/kernel/closure/bsdf_hair_principled.h b/intern/cycles/kernel/closure/bsdf_hair_principled.h new file mode 100644 index 00000000000..4ee58089384 --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_hair_principled.h @@ -0,0 +1,502 @@ +/* + * Copyright 2018 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. + */ + +#ifdef __KERNEL_CPU__ +#include <fenv.h> +#endif + +#include "kernel/kernel_color.h" + +#ifndef __BSDF_HAIR_PRINCIPLED_H__ +#define __BSDF_HAIR_PRINCIPLED_H__ + +CCL_NAMESPACE_BEGIN + +typedef ccl_addr_space struct PrincipledHairExtra { + /* Geometry data. */ + float4 geom; +} PrincipledHairExtra; + +typedef ccl_addr_space struct PrincipledHairBSDF { + SHADER_CLOSURE_BASE; + + /* Absorption coefficient. */ + float3 sigma; + /* Variance of the underlying logistic distribution. */ + float v; + /* Scale factor of the underlying logistic distribution. */ + float s; + /* Cuticle tilt angle. */ + float alpha; + /* IOR. */ + float eta; + /* Effective variance for the diffuse bounce only. */ + float m0_roughness; + + /* Extra closure. */ + PrincipledHairExtra *extra; +} PrincipledHairBSDF; + +static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledHairBSDF), "PrincipledHairBSDF is too large!"); +static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledHairExtra), "PrincipledHairExtra is too large!"); + +ccl_device_inline float cos_from_sin(const float s) +{ + return safe_sqrtf(1.0f - s*s); +} + +/* Gives the change in direction in the normal plane for the given angles and p-th-order scattering. */ +ccl_device_inline float delta_phi(int p, float gamma_o, float gamma_t) +{ + return 2.0f * p * gamma_t - 2.0f * gamma_o + p * M_PI_F; +} + +/* Remaps the given angle to [-pi, pi]. */ +ccl_device_inline float wrap_angle(float a) +{ + while(a > M_PI_F) { + a -= M_2PI_F; + } + while(a < -M_PI_F) { + a += M_2PI_F; + } + return a; +} + +/* Logistic distribution function. */ +ccl_device_inline float logistic(float x, float s) +{ + float v = expf(-fabsf(x)/s); + return v / (s * sqr(1.0f + v)); +} + +/* Logistic cumulative density function. */ +ccl_device_inline float logistic_cdf(float x, float s) +{ + float arg = -x/s; + /* expf() overflows if arg >= 89.0. */ + if(arg > 88.0f) { + return 0.0f; + } + else { + return 1.0f / (1.0f + expf(arg)); + } +} + +/* Numerical approximation to the Bessel function of the first kind. */ +ccl_device_inline float bessel_I0(float x) +{ + x = sqr(x); + float val = 1.0f + 0.25f*x; + float pow_x_2i = sqr(x); + uint64_t i_fac_2 = 1; + int pow_4_i = 16; + for(int i = 2; i < 10; i++) { + i_fac_2 *= i*i; + float newval = val + pow_x_2i / (pow_4_i * i_fac_2); + if(val == newval) { + return val; + } + val = newval; + pow_x_2i *= x; + pow_4_i *= 4; + } + return val; +} + +/* Logarithm of the Bessel function of the first kind. */ +ccl_device_inline float log_bessel_I0(float x) +{ + if (x > 12.0f) { + /* log(1/x) == -log(x) iff x > 0. + * This is only used with positive cosines */ + return x + 0.5f * (1.f / (8.0f * x) - M_LN_2PI_F - logf(x)); + } + else { + return logf(bessel_I0(x)); + } +} + +/* Logistic distribution limited to the interval [-pi, pi]. */ +ccl_device_inline float trimmed_logistic(float x, float s) +{ + /* The logistic distribution is symmetric and centered around zero, + * so logistic_cdf(x, s) = 1 - logistic_cdf(-x, s). + * Therefore, logistic_cdf(x, s)-logistic_cdf(-x, s) = 1 - 2*logistic_cdf(-x, s) */ + float scaling_fac = 1.0f - 2.0f*logistic_cdf(-M_PI_F, s); + float val = logistic(x, s); + return safe_divide(val, scaling_fac); +} + +/* Sampling function for the trimmed logistic function. */ +ccl_device_inline float sample_trimmed_logistic(float u, float s) +{ + float cdf_minuspi = logistic_cdf(-M_PI_F, s); + float x = -s*logf(1.0f / (u*(1.0f - 2.0f*cdf_minuspi) + cdf_minuspi) - 1.0f); + return clamp(x, -M_PI_F, M_PI_F); +} + +/* Azimuthal scattering function Np. */ +ccl_device_inline float azimuthal_scattering(float phi, + int p, + float s, + float gamma_o, + float gamma_t) +{ + float phi_o = wrap_angle(phi - delta_phi(p, gamma_o, gamma_t)); + float val = trimmed_logistic(phi_o, s); + return val; +} + +/* Longitudinal scattering function Mp. */ +ccl_device_inline float longitudinal_scattering(float sin_theta_i, + float cos_theta_i, + float sin_theta_o, + float cos_theta_o, + float v) +{ + float inv_v = 1.0f/v; + float cos_arg = cos_theta_i * cos_theta_o * inv_v; + float sin_arg = sin_theta_i * sin_theta_o * inv_v; + if(v <= 0.1f) { + float i0 = log_bessel_I0(cos_arg); + float val = expf(i0 - sin_arg - inv_v + 0.6931f + logf(0.5f*inv_v)); + return val; + } + else { + float i0 = bessel_I0(cos_arg); + float val = (expf(-sin_arg) * i0) / (sinhf(inv_v) * 2.0f * v); + return val; + } +} + +/* Combine the three values using their luminances. */ +ccl_device_inline float4 combine_with_energy(KernelGlobals *kg, float3 c) +{ + return make_float4(c.x, c.y, c.z, linear_rgb_to_gray(kg, c)); +} + +#ifdef __HAIR__ +/* Set up the hair closure. */ +ccl_device int bsdf_principled_hair_setup(ShaderData *sd, PrincipledHairBSDF *bsdf) +{ + bsdf->type = CLOSURE_BSDF_HAIR_PRINCIPLED_ID; + bsdf->v = clamp(bsdf->v, 0.001f, 1.0f); + bsdf->s = clamp(bsdf->s, 0.001f, 1.0f); + /* Apply Primary Reflection Roughness modifier. */ + bsdf->m0_roughness = clamp(bsdf->m0_roughness*bsdf->v, 0.001f, 1.0f); + + /* Map from roughness_u and roughness_v to variance and scale factor. */ + bsdf->v = sqr(0.726f*bsdf->v + 0.812f*sqr(bsdf->v) + 3.700f*pow20(bsdf->v)); + bsdf->s = (0.265f*bsdf->s + 1.194f*sqr(bsdf->s) + 5.372f*pow22(bsdf->s))*M_SQRT_PI_8_F; + bsdf->m0_roughness = sqr(0.726f*bsdf->m0_roughness + 0.812f*sqr(bsdf->m0_roughness) + 3.700f*pow20(bsdf->m0_roughness)); + + /* Compute local frame, aligned to curve tangent and ray direction. */ + float3 X = safe_normalize(sd->dPdu); + float3 Y = safe_normalize(cross(X, sd->I)); + float3 Z = safe_normalize(cross(X, Y)); + /* TODO: the solution below works where sd->Ng is the normal + * pointing from the center of the curve to the shading point. + * It doesn't work for triangles, see https://developer.blender.org/T43625 */ + + /* h -1..0..1 means the rays goes from grazing the hair, to hitting it at + * the center, to grazing the other edge. This is the sine of the angle + * between sd->Ng and Z, as seen from the tangent X. */ + + /* TODO: we convert this value to a cosine later and discard the sign, so + * we could probably save some operations. */ + float h = dot(cross(sd->Ng, X), Z); + + kernel_assert(fabsf(h) < 1.0f + 1e-4f); + kernel_assert(isfinite3_safe(Y)); + kernel_assert(isfinite_safe(h)); + + bsdf->extra->geom = make_float4(Y.x, Y.y, Y.z, h); + + return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG; +} + +#endif /* __HAIR__ */ + +/* Given the Fresnel term and transmittance, generate the attenuation terms for each bounce. */ +ccl_device_inline void hair_attenuation(KernelGlobals *kg, + float f, + float3 T, + float4 *Ap) +{ + /* Primary specular (R). */ + Ap[0] = make_float4(f, f, f, f); + + /* Transmission (TT). */ + float3 col = sqr(1.0f - f) * T; + Ap[1] = combine_with_energy(kg, col); + + /* Secondary specular (TRT). */ + col *= T*f; + Ap[2] = combine_with_energy(kg, col); + + /* Residual component (TRRT+). */ + col *= safe_divide_color(T*f, make_float3(1.0f, 1.0f, 1.0f) - T*f); + Ap[3] = combine_with_energy(kg, col); + + /* Normalize sampling weights. */ + float totweight = Ap[0].w + Ap[1].w + Ap[2].w + Ap[3].w; + float fac = safe_divide(1.0f, totweight); + + Ap[0].w *= fac; + Ap[1].w *= fac; + Ap[2].w *= fac; + Ap[3].w *= fac; +} + +/* Given the tilt angle, generate the rotated theta_i for the different bounces. */ +ccl_device_inline void hair_alpha_angles(float sin_theta_i, + float cos_theta_i, + float alpha, + float *angles) +{ + float sin_1alpha = sinf(alpha); + float cos_1alpha = cos_from_sin(sin_1alpha); + float sin_2alpha = 2.0f*sin_1alpha*cos_1alpha; + float cos_2alpha = sqr(cos_1alpha) - sqr(sin_1alpha); + float sin_4alpha = 2.0f*sin_2alpha*cos_2alpha; + float cos_4alpha = sqr(cos_2alpha) - sqr(sin_2alpha); + + angles[0] = sin_theta_i*cos_2alpha + cos_theta_i*sin_2alpha; + angles[1] = fabsf(cos_theta_i*cos_2alpha - sin_theta_i*sin_2alpha); + angles[2] = sin_theta_i*cos_1alpha - cos_theta_i*sin_1alpha; + angles[3] = fabsf(cos_theta_i*cos_1alpha + sin_theta_i*sin_1alpha); + angles[4] = sin_theta_i*cos_4alpha - cos_theta_i*sin_4alpha; + angles[5] = fabsf(cos_theta_i*cos_4alpha + sin_theta_i*sin_4alpha); +} + +/* Evaluation function for our shader. */ +ccl_device float3 bsdf_principled_hair_eval(KernelGlobals *kg, + const ShaderData *sd, + const ShaderClosure *sc, + const float3 omega_in, + float *pdf) +{ + kernel_assert(isfinite3_safe(sd->P) && isfinite_safe(sd->ray_length)); + + const PrincipledHairBSDF *bsdf = (const PrincipledHairBSDF*) sc; + float3 Y = float4_to_float3(bsdf->extra->geom); + + float3 X = safe_normalize(sd->dPdu); + kernel_assert(fabsf(dot(X, Y)) < 1e-4f); + float3 Z = safe_normalize(cross(X, Y)); + + float3 wo = make_float3(dot(sd->I, X), dot(sd->I, Y), dot(sd->I, Z)); + float3 wi = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + float sin_theta_o = wo.x; + float cos_theta_o = cos_from_sin(sin_theta_o); + float phi_o = atan2f(wo.z, wo.y); + + float sin_theta_t = sin_theta_o / bsdf->eta; + float cos_theta_t = cos_from_sin(sin_theta_t); + + float sin_gamma_o = bsdf->extra->geom.w; + float cos_gamma_o = cos_from_sin(sin_gamma_o); + float gamma_o = safe_asinf(sin_gamma_o); + + float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o)); + float cos_gamma_t = cos_from_sin(sin_gamma_t); + float gamma_t = safe_asinf(sin_gamma_t); + + float3 T = exp3(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t)); + float4 Ap[4]; + hair_attenuation(kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap); + + float sin_theta_i = wi.x; + float cos_theta_i = cos_from_sin(sin_theta_i); + float phi_i = atan2f(wi.z, wi.y); + + float phi = phi_i - phi_o; + + float angles[6]; + hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles); + + float4 F; + float Mp, Np; + + /* Primary specular (R). */ + Mp = longitudinal_scattering(angles[0], angles[1], sin_theta_o, cos_theta_o, bsdf->m0_roughness); + Np = azimuthal_scattering(phi, 0, bsdf->s, gamma_o, gamma_t); + F = Ap[0] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); + + /* Transmission (TT). */ + Mp = longitudinal_scattering(angles[2], angles[3], sin_theta_o, cos_theta_o, 0.25f*bsdf->v); + Np = azimuthal_scattering(phi, 1, bsdf->s, gamma_o, gamma_t); + F += Ap[1] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); + + /* Secondary specular (TRT). */ + Mp = longitudinal_scattering(angles[4], angles[5], sin_theta_o, cos_theta_o, 4.0f*bsdf->v); + Np = azimuthal_scattering(phi, 2, bsdf->s, gamma_o, gamma_t); + F += Ap[2] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); + + /* Residual component (TRRT+). */ + Mp = longitudinal_scattering(sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f*bsdf->v); + Np = M_1_2PI_F; + F += Ap[3] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); + + *pdf = F.w; + return float4_to_float3(F); +} + +/* Sampling function for the hair shader. */ +ccl_device int bsdf_principled_hair_sample(KernelGlobals *kg, + const ShaderClosure *sc, + ShaderData *sd, + float randu, + float randv, + float3 *eval, + float3 *omega_in, + float3 *domega_in_dx, + float3 *domega_in_dy, + float *pdf) +{ + PrincipledHairBSDF *bsdf = (PrincipledHairBSDF*) sc; + + float3 Y = float4_to_float3(bsdf->extra->geom); + + float3 X = safe_normalize(sd->dPdu); + kernel_assert(fabsf(dot(X, Y)) < 1e-4f); + float3 Z = safe_normalize(cross(X, Y)); + + float3 wo = make_float3(dot(sd->I, X), dot(sd->I, Y), dot(sd->I, Z)); + + float2 u[2]; + u[0] = make_float2(randu, randv); + u[1].x = lcg_step_float_addrspace(&sd->lcg_state); + u[1].y = lcg_step_float_addrspace(&sd->lcg_state); + + float sin_theta_o = wo.x; + float cos_theta_o = cos_from_sin(sin_theta_o); + float phi_o = atan2f(wo.z, wo.y); + + float sin_theta_t = sin_theta_o / bsdf->eta; + float cos_theta_t = cos_from_sin(sin_theta_t); + + float sin_gamma_o = bsdf->extra->geom.w; + float cos_gamma_o = cos_from_sin(sin_gamma_o); + float gamma_o = safe_asinf(sin_gamma_o); + + float sin_gamma_t = sin_gamma_o * cos_theta_o / sqrtf(sqr(bsdf->eta) - sqr(sin_theta_o)); + float cos_gamma_t = cos_from_sin(sin_gamma_t); + float gamma_t = safe_asinf(sin_gamma_t); + + float3 T = exp3(-bsdf->sigma * (2.0f * cos_gamma_t / cos_theta_t)); + float4 Ap[4]; + hair_attenuation(kg, fresnel_dielectric_cos(cos_theta_o * cos_gamma_o, bsdf->eta), T, Ap); + + int p = 0; + for(; p < 3; p++) { + if(u[0].x < Ap[p].w) { + break; + } + u[0].x -= Ap[p].w; + } + + float v = bsdf->v; + if(p == 1) { + v *= 0.25f; + } + if(p >= 2) { + v *= 4.0f; + } + + u[1].x = max(u[1].x, 1e-5f); + float fac = 1.0f + v*logf(u[1].x + (1.0f - u[1].x)*expf(-2.0f/v)); + float sin_theta_i = -fac * sin_theta_o + cos_from_sin(fac) * cosf(M_2PI_F * u[1].y) * cos_theta_o; + float cos_theta_i = cos_from_sin(sin_theta_i); + + float angles[6]; + if(p < 3) { + hair_alpha_angles(sin_theta_i, cos_theta_i, -bsdf->alpha, angles); + sin_theta_i = angles[2*p]; + cos_theta_i = angles[2*p+1]; + } + + float phi; + if(p < 3) { + phi = delta_phi(p, gamma_o, gamma_t) + sample_trimmed_logistic(u[0].y, bsdf->s); + } + else { + phi = M_2PI_F*u[0].y; + } + float phi_i = phi_o + phi; + + hair_alpha_angles(sin_theta_i, cos_theta_i, bsdf->alpha, angles); + + float4 F; + float Mp, Np; + + /* Primary specular (R). */ + Mp = longitudinal_scattering(angles[0], angles[1], sin_theta_o, cos_theta_o, bsdf->m0_roughness); + Np = azimuthal_scattering(phi, 0, bsdf->s, gamma_o, gamma_t); + F = Ap[0] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); + + /* Transmission (TT). */ + Mp = longitudinal_scattering(angles[2], angles[3], sin_theta_o, cos_theta_o, 0.25f*bsdf->v); + Np = azimuthal_scattering(phi, 1, bsdf->s, gamma_o, gamma_t); + F += Ap[1] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); + + /* Secondary specular (TRT). */ + Mp = longitudinal_scattering(angles[4], angles[5], sin_theta_o, cos_theta_o, 4.0f*bsdf->v); + Np = azimuthal_scattering(phi, 2, bsdf->s, gamma_o, gamma_t); + F += Ap[2] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); + + /* Residual component (TRRT+). */ + Mp = longitudinal_scattering(sin_theta_i, cos_theta_i, sin_theta_o, cos_theta_o, 4.0f*bsdf->v); + Np = M_1_2PI_F; + F += Ap[3] * Mp * Np; + kernel_assert(isfinite3_safe(float4_to_float3(F))); + + *eval = float4_to_float3(F); + *pdf = F.w; + + *omega_in = X*sin_theta_i + Y*cos_theta_i*cosf(phi_i) + Z*cos_theta_i*sinf(phi_i); + +#ifdef __RAY_DIFFERENTIALS__ + float3 N = safe_normalize(sd->I + *omega_in); + *domega_in_dx = (2 * dot(N, sd->dI.dx)) * N - sd->dI.dx; + *domega_in_dy = (2 * dot(N, sd->dI.dy)) * N - sd->dI.dy; +#endif + + return LABEL_GLOSSY|((p == 0)? LABEL_REFLECT : LABEL_TRANSMIT); +} + +/* Implements Filter Glossy by capping the effective roughness. */ +ccl_device void bsdf_principled_hair_blur(ShaderClosure *sc, float roughness) +{ + PrincipledHairBSDF *bsdf = (PrincipledHairBSDF*)sc; + + bsdf->v = fmaxf(roughness, bsdf->v); + bsdf->s = fmaxf(roughness, bsdf->s); + bsdf->m0_roughness = fmaxf(roughness, bsdf->m0_roughness); +} + +CCL_NAMESPACE_END + +#endif /* __BSDF_HAIR_PRINCIPLED_H__ */ diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h index e35267f02bf..dea0c742ed7 100644 --- a/intern/cycles/kernel/geom/geom_curve.h +++ b/intern/cycles/kernel/geom/geom_curve.h @@ -23,6 +23,33 @@ CCL_NAMESPACE_BEGIN #ifdef __HAIR__ +/* Interpolation of curve geometry */ + +ccl_device_inline float3 curvetangent(float t, float3 p0, float3 p1, float3 p2, float3 p3) +{ + float fc = 0.71f; + float data[4]; + float t2 = t * t; + data[0] = -3.0f * fc * t2 + 4.0f * fc * t - fc; + data[1] = 3.0f * (2.0f - fc) * t2 + 2.0f * (fc - 3.0f) * t; + data[2] = 3.0f * (fc - 2.0f) * t2 + 2.0f * (3.0f - 2.0f * fc) * t + fc; + data[3] = 3.0f * fc * t2 - 2.0f * fc * t; + return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3; +} + +ccl_device_inline float3 curvepoint(float t, float3 p0, float3 p1, float3 p2, float3 p3) +{ + float data[4]; + float fc = 0.71f; + float t2 = t * t; + float t3 = t2 * t; + data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t; + data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f; + data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t; + data[3] = fc * t3 - fc * t2; + return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3; +} + /* Reading attributes on various curve elements */ ccl_device float curve_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy) diff --git a/intern/cycles/kernel/geom/geom_curve_intersect.h b/intern/cycles/kernel/geom/geom_curve_intersect.h index 46c3f408f0b..4cfbe21685c 100644 --- a/intern/cycles/kernel/geom/geom_curve_intersect.h +++ b/intern/cycles/kernel/geom/geom_curve_intersect.h @@ -752,31 +752,6 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals *kg, #endif } -ccl_device_inline float3 curvetangent(float t, float3 p0, float3 p1, float3 p2, float3 p3) -{ - float fc = 0.71f; - float data[4]; - float t2 = t * t; - data[0] = -3.0f * fc * t2 + 4.0f * fc * t - fc; - data[1] = 3.0f * (2.0f - fc) * t2 + 2.0f * (fc - 3.0f) * t; - data[2] = 3.0f * (fc - 2.0f) * t2 + 2.0f * (3.0f - 2.0f * fc) * t + fc; - data[3] = 3.0f * fc * t2 - 2.0f * fc * t; - return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3; -} - -ccl_device_inline float3 curvepoint(float t, float3 p0, float3 p1, float3 p2, float3 p3) -{ - float data[4]; - float fc = 0.71f; - float t2 = t * t; - float t3 = t2 * t; - data[0] = -fc * t3 + 2.0f * fc * t2 - fc * t; - data[1] = (2.0f - fc) * t3 + (fc - 3.0f) * t2 + 1.0f; - data[2] = (fc - 2.0f) * t3 + (3.0f - 2.0f * fc) * t2 + fc * t; - data[3] = fc * t3 - fc * t2; - return data[0] * p0 + data[1] * p1 + data[2] * p2 + data[3] * p3; -} - ccl_device_inline float3 curve_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h index d1ae10a0384..3f7e264fbee 100644 --- a/intern/cycles/kernel/kernel_compat_opencl.h +++ b/intern/cycles/kernel/kernel_compat_opencl.h @@ -123,6 +123,7 @@ #define fmaxf(x, y) fmax(((float)(x)), ((float)(y))) #define fminf(x, y) fmin(((float)(x)), ((float)(y))) #define fmodf(x, y) fmod((float)(x), (float)(y)) +#define sinhf(x) sinh(((float)(x))) #ifndef __CL_USE_NATIVE__ # define sinf(x) native_sin(((float)(x))) diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index 32cb924d25f..262d7df1364 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -72,24 +72,17 @@ ccl_device_inline float rect_light_sample(float3 P, float y0 = dot(dir, y); float x1 = x0 + axisu_len; float y1 = y0 + axisv_len; - /* Create vectors to four vertices. */ - float3 v00 = make_float3(x0, y0, z0); - float3 v01 = make_float3(x0, y1, z0); - float3 v10 = make_float3(x1, y0, z0); - float3 v11 = make_float3(x1, y1, z0); - /* Compute normals to edges. */ - float3 n0 = normalize(cross(v00, v10)); - float3 n1 = normalize(cross(v10, v11)); - float3 n2 = normalize(cross(v11, v01)); - float3 n3 = normalize(cross(v01, v00)); /* Compute internal angles (gamma_i). */ - float g0 = safe_acosf(-dot(n0, n1)); - float g1 = safe_acosf(-dot(n1, n2)); - float g2 = safe_acosf(-dot(n2, n3)); - float g3 = safe_acosf(-dot(n3, n0)); + float4 diff = make_float4(x0, y1, x1, y0) - make_float4(x1, y0, x0, y1); + float4 nz = make_float4(y0, x1, y1, x0) * diff; + nz = nz / sqrt(z0 * z0 * diff * diff + nz * nz); + float g0 = safe_acosf(-nz.x * nz.y); + float g1 = safe_acosf(-nz.y * nz.z); + float g2 = safe_acosf(-nz.z * nz.w); + float g3 = safe_acosf(-nz.w * nz.x); /* Compute predefined constants. */ - float b0 = n0.z; - float b1 = n2.z; + float b0 = nz.x; + float b1 = nz.z; float b0sq = b0 * b0; float k = M_2PI_F - g2 - g3; /* Compute solid angle from internal angles. */ diff --git a/intern/cycles/kernel/kernel_montecarlo.h b/intern/cycles/kernel/kernel_montecarlo.h index 49dc1f08cc1..09a3fe8f23d 100644 --- a/intern/cycles/kernel/kernel_montecarlo.h +++ b/intern/cycles/kernel/kernel_montecarlo.h @@ -184,6 +184,35 @@ ccl_device float2 regular_polygon_sample(float corners, float rotation, float u, return make_float2(cr*p.x - sr*p.y, sr*p.x + cr*p.y); } +ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N) +{ + float3 R = 2*dot(N, I)*N - I; + if(dot(Ng, R) >= 0.05f) { + return N; + } + + /* Form coordinate system with Ng as the Z axis and N inside the X-Z-plane. + * The X axis is found by normalizing the component of N that's orthogonal to Ng. + * The Y axis isn't actually needed. + */ + float3 X = normalize(N - dot(N, Ng)*Ng); + + /* Calculate N.z and N.x in the local coordinate system. */ + float Iz = dot(I, Ng); + float Ix2 = sqr(dot(I, X)), Iz2 = sqr(Iz); + float Ix2Iz2 = Ix2 + Iz2; + + float a = sqrtf(Ix2*(Ix2Iz2 - sqr(0.05f))); + float b = Iz*0.05f + Ix2Iz2; + float c = (a + b > 0.0f)? (a + b) : (-a + b); + + float Nz = sqrtf(0.5f * c * (1.0f / Ix2Iz2)); + float Nx = sqrtf(1.0f - sqr(Nz)); + + /* Transform back into global coordinates. */ + return Nx*X + Nz*Ng; +} + CCL_NAMESPACE_END #endif /* __KERNEL_MONTECARLO_CL__ */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 69ee66b3dd5..85548484873 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -54,7 +54,7 @@ CCL_NAMESPACE_BEGIN #define PRIM_NONE (~0) #define LAMP_NONE (~0) -#define VOLUME_STACK_SIZE 16 +#define VOLUME_STACK_SIZE 32 /* Split kernel constants */ #define WORK_POOL_SIZE_GPU 64 diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index a7072c3ad03..d71761a97bc 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -91,7 +91,7 @@ ccl_device_inline bool volume_shader_sample(KernelGlobals *kg, ccl_device float3 volume_color_transmittance(float3 sigma, float t) { - return make_float3(expf(-sigma.x * t), expf(-sigma.y * t), expf(-sigma.z * t)); + return exp3(-sigma * t); } ccl_device float kernel_volume_channel_get(float3 value, int channel) @@ -234,7 +234,7 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, sum += (-sigma_t * (new_t - t)); if((i & 0x07) == 0) { /* ToDo: Other interval? */ - tp = *throughput * make_float3(expf(sum.x), expf(sum.y), expf(sum.z)); + tp = *throughput * exp3(sum); /* stop if nearly all light is blocked */ if(tp.x < tp_eps && tp.y < tp_eps && tp.z < tp_eps) @@ -246,7 +246,7 @@ ccl_device void kernel_volume_shadow_heterogeneous(KernelGlobals *kg, t = new_t; if(t == ray->t) { /* Update throughput in case we haven't done it above */ - tp = *throughput * make_float3(expf(sum.x), expf(sum.y), expf(sum.z)); + tp = *throughput * exp3(sum); break; } } diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp index 581b38e65c0..8c7ae30725c 100644 --- a/intern/cycles/kernel/osl/osl_closures.cpp +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -4,7 +4,7 @@ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. * All Rights Reserved. * - * Modifications Copyright 2011, Blender Foundation. + * Modifications Copyright 2011-2018, Blender Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -59,6 +59,7 @@ #include "kernel/closure/bsdf_ashikhmin_shirley.h" #include "kernel/closure/bsdf_toon.h" #include "kernel/closure/bsdf_hair.h" +#include "kernel/closure/bsdf_hair_principled.h" #include "kernel/closure/bsdf_principled_diffuse.h" #include "kernel/closure/bsdf_principled_sheen.h" #include "kernel/closure/volume.h" @@ -176,6 +177,61 @@ BSDF_CLOSURE_CLASS_BEGIN(PrincipledSheen, principled_sheen, PrincipledSheenBsdf, CLOSURE_FLOAT3_PARAM(PrincipledSheenClosure, params.N), BSDF_CLOSURE_CLASS_END(PrincipledSheen, principled_sheen) +/* PRINCIPLED HAIR BSDF */ +class PrincipledHairClosure : public CBSDFClosure { +public: + PrincipledHairBSDF params; + + PrincipledHairBSDF *alloc(ShaderData *sd, int path_flag, float3 weight) + { + PrincipledHairBSDF *bsdf = (PrincipledHairBSDF*)bsdf_alloc_osl(sd, sizeof(PrincipledHairBSDF), weight, ¶ms); + if(!bsdf) { + return NULL; + } + + PrincipledHairExtra *extra = (PrincipledHairExtra*)closure_alloc_extra(sd, sizeof(PrincipledHairExtra)); + if(!extra) { + return NULL; + } + + bsdf->extra = extra; + return bsdf; + } + + void setup(ShaderData *sd, int path_flag, float3 weight) + { + if(!skip(sd, path_flag, LABEL_GLOSSY)) + { + PrincipledHairBSDF *bsdf = (PrincipledHairBSDF*)alloc(sd, path_flag, weight); + if (!bsdf) + { + return; + } + + sd->flag |= (bsdf) ? bsdf_principled_hair_setup(sd, bsdf) : 0; + } + } +}; + +static ClosureParam *closure_bsdf_principled_hair_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(PrincipledHairClosure, params.N), + CLOSURE_FLOAT3_PARAM(PrincipledHairClosure, params.sigma), + CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.v), + CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.s), + CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.m0_roughness), + CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.alpha), + CLOSURE_FLOAT_PARAM(PrincipledHairClosure, params.eta), + CLOSURE_STRING_KEYPARAM(PrincipledHairClosure, label, "label"), + CLOSURE_FINISH_PARAM(PrincipledHairClosure) + }; + + return params; +} + +CCLOSURE_PREPARE(closure_bsdf_principled_hair_prepare, PrincipledHairClosure) + /* DISNEY PRINCIPLED CLEARCOAT */ class PrincipledClearcoatClosure : public CBSDFClosure { public: @@ -322,6 +378,9 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) register_closure(ss, "hair_transmission", id++, bsdf_hair_transmission_params(), bsdf_hair_transmission_prepare); + register_closure(ss, "principled_hair", id++, + closure_bsdf_principled_hair_params(), closure_bsdf_principled_hair_prepare); + register_closure(ss, "henyey_greenstein", id++, closure_henyey_greenstein_params(), closure_henyey_greenstein_prepare); register_closure(ss, "absorption", id++, diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h index 857cc84afd2..d9aeb9ab9fb 100644 --- a/intern/cycles/kernel/osl/osl_closures.h +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -79,6 +79,7 @@ void closure_bsdf_microfacet_multi_ggx_fresnel_prepare(OSL::RendererServices *, void closure_bsdf_microfacet_multi_ggx_glass_fresnel_prepare(OSL::RendererServices *, int id, void *data); void closure_bsdf_microfacet_multi_ggx_aniso_fresnel_prepare(OSL::RendererServices *, int id, void *data); void closure_bsdf_principled_clearcoat_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_principled_hair_prepare(OSL::RendererServices *, int id, void *data); #define CCLOSURE_PREPARE(name, classname) \ void name(RendererServices *, int id, void *data) \ diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index 9ee78d160a4..4740db27d4e 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -85,6 +85,7 @@ set(SRC_OSL node_wave_texture.osl node_wireframe.osl node_hair_bsdf.osl + node_principled_hair_bsdf.osl node_uv_map.osl node_principled_bsdf.osl node_rgb_to_bw.osl diff --git a/intern/cycles/kernel/shaders/node_bump.osl b/intern/cycles/kernel/shaders/node_bump.osl index 7f01cf2ca91..a2a4468d5f3 100644 --- a/intern/cycles/kernel/shaders/node_bump.osl +++ b/intern/cycles/kernel/shaders/node_bump.osl @@ -64,5 +64,7 @@ surface node_bump( if (use_object_space) { NormalOut = normalize(transform("object", "world", NormalOut)); } + + NormalOut = ensure_valid_reflection(Ng, I, NormalOut); } diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/shaders/node_normal_map.osl index 41bcac4fb10..fda6f12a5da 100644 --- a/intern/cycles/kernel/shaders/node_normal_map.osl +++ b/intern/cycles/kernel/shaders/node_normal_map.osl @@ -88,5 +88,7 @@ shader node_normal_map( if (Strength != 1.0) Normal = normalize(NormalIn + (Normal - NormalIn) * max(Strength, 0.0)); + + Normal = ensure_valid_reflection(Ng, I, Normal); } diff --git a/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl b/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl new file mode 100644 index 00000000000..757a88f8ece --- /dev/null +++ b/intern/cycles/kernel/shaders/node_principled_hair_bsdf.osl @@ -0,0 +1,105 @@ +/* + * Copyright 2018 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" + +color log3(color a) +{ + return color(log(a[0]), log(a[1]), log(a[2])); +} + +color sigma_from_concentration(float eumelanin, float pheomelanin) +{ + return eumelanin*color(0.506, 0.841, 1.653) + pheomelanin*color(0.343, 0.733, 1.924); +} + +color sigma_from_reflectance(color c, float azimuthal_roughness) +{ + float x = azimuthal_roughness; + float roughness_fac = (((((0.245*x) + 5.574)*x - 10.73)*x + 2.532)*x - 0.215)*x + 5.969; + color sigma = log3(c) / roughness_fac; + return sigma * sigma; +} + +shader node_principled_hair_bsdf( + color Color = color(0.017513, 0.005763, 0.002059), + float Melanin = 0.8, + float MelaninRedness = 1.0, + float RandomColor = 0.0, + color Tint = 1.0, + color AbsorptionCoefficient = color(0.245531, 0.52, 1.365), + normal Normal = Ng, + string parametrization = "Absorption coefficient", + float Offset = radians(2), + float Roughness = 0.3, + float RadialRoughness = 0.3, + float RandomRoughness = 0.0, + float Coat = 0.0, + float IOR = 1.55, + string AttrRandom = "geom:curve_random", + float Random = 0.0, + + output closure color BSDF = 0) +{ + /* Get random value from curve in none is specified. */ + float random_value = 0.0; + + if (isconnected(Random)) { + random_value = Random; + } + else { + getattribute(AttrRandom, random_value); + } + + /* Compute roughness. */ + float factor_random_roughness = 1.0 + 2.0*(random_value - 0.5)*RandomRoughness; + float m0_roughness = 1.0 - clamp(Coat, 0.0, 1.0); + float roughness = Roughness*factor_random_roughness; + float radial_roughness = RadialRoughness*factor_random_roughness; + + /* Compute absorption. */ + color sigma; + + if (parametrization == "Absorption coefficient") { + sigma = AbsorptionCoefficient; + } + else if (parametrization == "Melanin concentration") { + /* Randomize melanin. */ + float factor_random_color = 1.0 + 2.0*(random_value - 0.5) * RandomColor; + float melanin = Melanin * factor_random_color; + + /* Map melanin 0..inf from more perceptually linear 0..1. */ + melanin = -log(max(1.0 - melanin, 0.0001)); + + /* Benedikt Bitterli's melanin ratio remapping. */ + float eumelanin = melanin * (1.0 - MelaninRedness); + float pheomelanin = melanin * MelaninRedness; + color melanin_sigma = sigma_from_concentration(eumelanin, pheomelanin); + + /* Optional tint. */ + color tint_sigma = sigma_from_reflectance(Tint, radial_roughness); + sigma = melanin_sigma + tint_sigma; + } + else if (parametrization == "Direct coloring"){ + sigma = sigma_from_reflectance(Color, radial_roughness); + } + else { + /* Fallback to brownish hair, same as defaults for melanin. */ + sigma = sigma_from_concentration(0.0, 0.8054375); + } + + BSDF = principled_hair(Normal, sigma, roughness, radial_roughness, m0_roughness, Offset, IOR); +} diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h index 82223ca0219..4a8378796ba 100644 --- a/intern/cycles/kernel/shaders/stdosl.h +++ b/intern/cycles/kernel/shaders/stdosl.h @@ -282,6 +282,36 @@ point rotate (point p, float angle, point a, point b) return transform (M, p-a) + a; } +normal ensure_valid_reflection(normal Ng, vector I, normal N) +{ + float sqr(float x) { return x*x; } + + vector R = 2*dot(N, I)*N - I; + if (dot(Ng, R) >= 0.05) { + return N; + } + + /* Form coordinate system with Ng as the Z axis and N inside the X-Z-plane. + * The X axis is found by normalizing the component of N that's orthogonal to Ng. + * The Y axis isn't actually needed. + */ + vector X = normalize(N - dot(N, Ng)*Ng); + + /* Calculate N.z and N.x in the local coordinate system. */ + float Ix = dot(I, X), Iz = dot(I, Ng); + float Ix2 = sqr(dot(I, X)), Iz2 = sqr(dot(I, Ng)); + float Ix2Iz2 = Ix2 + Iz2; + + float a = sqrt(Ix2*(Ix2Iz2 - sqr(0.05))); + float b = Iz*0.05 + Ix2Iz2; + float c = (a + b > 0.0)? (a + b) : (-a + b); + + float Nz = sqrt(0.5 * c * (1.0 / Ix2Iz2)); + float Nx = sqrt(1.0 - sqr(Nz)); + + /* Transform back into global coordinates. */ + return Nx*X + Nz*Ng; +} // Color functions @@ -554,6 +584,7 @@ closure color bssrdf(string method, normal N, vector radius, color albedo) BUILT // 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; +closure color principled_hair(normal N, color sigma, float roughnessu, float roughnessv, float coat, float alpha, float eta) BUILTIN; // Volume closure color henyey_greenstein(float g) BUILTIN; diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index 4de9cfb88db..aa253223c93 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -16,6 +16,21 @@ CCL_NAMESPACE_BEGIN +/* Hair Melanin */ + +ccl_device_inline float3 sigma_from_concentration(float eumelanin, float pheomelanin) +{ + return eumelanin*make_float3(0.506f, 0.841f, 1.653f) + pheomelanin*make_float3(0.343f, 0.733f, 1.924f); +} + +ccl_device_inline float3 sigma_from_reflectance(float3 color, float azimuthal_roughness) +{ + float x = azimuthal_roughness; + float roughness_fac = (((((0.245f*x) + 5.574f)*x - 10.73f)*x + 2.532f)*x - 0.215f)*x + 5.969f; + float3 sigma = log3(color) / roughness_fac; + return sigma * sigma; +} + /* Closure Nodes */ ccl_device void svm_node_glass_setup(ShaderData *sd, MicrofacetBsdf *bsdf, int type, float eta, float roughness, bool refract) @@ -243,7 +258,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * float3 spec_weight = weight * specular_weight; MicrofacetBsdf *bsdf = (MicrofacetBsdf*)bsdf_alloc(sd, sizeof(MicrofacetBsdf), spec_weight); - if(!bsdf){ + if(!bsdf) { break; } @@ -722,6 +737,107 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * break; } #ifdef __HAIR__ + case CLOSURE_BSDF_HAIR_PRINCIPLED_ID: { + uint4 data_node2 = read_node(kg, offset); + uint4 data_node3 = read_node(kg, offset); + uint4 data_node4 = read_node(kg, offset); + + float3 weight = sd->svm_closure_weight * mix_weight; + + uint offset_ofs, ior_ofs, color_ofs, parametrization; + decode_node_uchar4(data_node.y, &offset_ofs, &ior_ofs, &color_ofs, ¶metrization); + float alpha = stack_load_float_default(stack, offset_ofs, data_node.z); + float ior = stack_load_float_default(stack, ior_ofs, data_node.w); + + uint coat_ofs, melanin_ofs, melanin_redness_ofs, absorption_coefficient_ofs; + decode_node_uchar4(data_node2.x, &coat_ofs, &melanin_ofs, &melanin_redness_ofs, &absorption_coefficient_ofs); + + uint tint_ofs, random_ofs, random_color_ofs, random_roughness_ofs; + decode_node_uchar4(data_node3.x, &tint_ofs, &random_ofs, &random_color_ofs, &random_roughness_ofs); + + const AttributeDescriptor attr_descr_random = find_attribute(kg, sd, data_node4.y); + float random = 0.0f; + if (attr_descr_random.offset != ATTR_STD_NOT_FOUND) { + random = primitive_attribute_float(kg, sd, attr_descr_random, NULL, NULL); + } + else { + random = stack_load_float_default(stack, random_ofs, data_node3.y); + } + + + PrincipledHairBSDF *bsdf = (PrincipledHairBSDF*)bsdf_alloc(sd, sizeof(PrincipledHairBSDF), weight); + if(bsdf) { + PrincipledHairExtra *extra = (PrincipledHairExtra*)closure_alloc_extra(sd, sizeof(PrincipledHairExtra)); + + if (!extra) + break; + + /* Random factors range: [-randomization/2, +randomization/2]. */ + float random_roughness = stack_load_float_default(stack, random_roughness_ofs, data_node3.w); + float factor_random_roughness = 1.0f + 2.0f*(random - 0.5f)*random_roughness; + float roughness = param1 * factor_random_roughness; + float radial_roughness = param2 * factor_random_roughness; + + /* Remap Coat value to [0, 100]% of Roughness. */ + float coat = stack_load_float_default(stack, coat_ofs, data_node2.y); + float m0_roughness = 1.0f - clamp(coat, 0.0f, 1.0f); + + bsdf->N = N; + bsdf->v = roughness; + bsdf->s = radial_roughness; + bsdf->m0_roughness = m0_roughness; + bsdf->alpha = alpha; + bsdf->eta = ior; + bsdf->extra = extra; + + switch(parametrization) { + case NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION: { + float3 absorption_coefficient = stack_load_float3(stack, absorption_coefficient_ofs); + bsdf->sigma = absorption_coefficient; + break; + } + case NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION: { + float melanin = stack_load_float_default(stack, melanin_ofs, data_node2.z); + float melanin_redness = stack_load_float_default(stack, melanin_redness_ofs, data_node2.w); + + /* Randomize melanin. */ + float random_color = stack_load_float_default(stack, random_color_ofs, data_node3.z); + random_color = clamp(random_color, 0.0f, 1.0f); + float factor_random_color = 1.0f + 2.0f * (random - 0.5f) * random_color; + melanin *= factor_random_color; + + /* Map melanin 0..inf from more perceptually linear 0..1. */ + melanin = -logf(fmaxf(1.0f - melanin, 0.0001f)); + + /* Benedikt Bitterli's melanin ratio remapping. */ + float eumelanin = melanin * (1.0f - melanin_redness); + float pheomelanin = melanin * melanin_redness; + float3 melanin_sigma = sigma_from_concentration(eumelanin, pheomelanin); + + /* Optional tint. */ + float3 tint = stack_load_float3(stack, tint_ofs); + float3 tint_sigma = sigma_from_reflectance(tint, radial_roughness); + + bsdf->sigma = melanin_sigma + tint_sigma; + break; + } + case NODE_PRINCIPLED_HAIR_REFLECTANCE: { + float3 color = stack_load_float3(stack, color_ofs); + bsdf->sigma = sigma_from_reflectance(color, radial_roughness); + break; + } + default: { + /* Fallback to brownish hair, same as defaults for melanin. */ + kernel_assert(!"Invalid Principled Hair parametrization!"); + bsdf->sigma = sigma_from_concentration(0.0f, 0.8054375f); + break; + } + } + + sd->flag |= bsdf_principled_hair_setup(sd, bsdf); + } + break; + } case CLOSURE_BSDF_HAIR_REFLECTION_ID: case CLOSURE_BSDF_HAIR_TRANSMISSION_ID: { float3 weight = sd->svm_closure_weight * mix_weight; @@ -764,7 +880,7 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * break; } -#endif +#endif /* __HAIR__ */ #ifdef __SUBSURFACE__ case CLOSURE_BSSRDF_CUBIC_ID: diff --git a/intern/cycles/kernel/svm/svm_displace.h b/intern/cycles/kernel/svm/svm_displace.h index b85eb9c0458..0f5b3abef87 100644 --- a/intern/cycles/kernel/svm/svm_displace.h +++ b/intern/cycles/kernel/svm/svm_displace.h @@ -75,6 +75,8 @@ ccl_device void svm_node_set_bump(KernelGlobals *kg, ShaderData *sd, float *stac object_normal_transform(kg, sd, &normal_out); } + normal_out = ensure_valid_reflection(sd->Ng, sd->I, normal_out); + stack_store_float3(stack, node.w, normal_out); #endif } diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index 7c207083929..45c38d64763 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -345,6 +345,8 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st N = safe_normalize(sd->N + (N - sd->N)*strength); } + N = ensure_valid_reflection(sd->Ng, sd->I, N); + if(is_zero(N)) { N = sd->N; } diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index e03ad3a0cfe..910537a2539 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -418,6 +418,13 @@ typedef enum ShaderType { SHADER_TYPE_BUMP, } ShaderType; +typedef enum NodePrincipledHairParametrization { + NODE_PRINCIPLED_HAIR_REFLECTANCE = 0, + NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION = 1, + NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION = 2, + NODE_PRINCIPLED_HAIR_NUM, +} NodePrincipledHairParametrization; + /* Closure */ typedef enum ClosureType { @@ -464,6 +471,7 @@ typedef enum ClosureType { CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID, CLOSURE_BSDF_SHARP_GLASS_ID, + CLOSURE_BSDF_HAIR_PRINCIPLED_ID, CLOSURE_BSDF_HAIR_TRANSMISSION_ID, /* Special cases */ @@ -495,7 +503,7 @@ typedef enum ClosureType { /* watch this, being lazy with memory usage */ #define CLOSURE_IS_BSDF(type) (type <= CLOSURE_BSDF_TRANSPARENT_ID) #define CLOSURE_IS_BSDF_DIFFUSE(type) (type >= CLOSURE_BSDF_DIFFUSE_ID && type <= CLOSURE_BSDF_DIFFUSE_TOON_ID) -#define CLOSURE_IS_BSDF_GLOSSY(type) (type >= CLOSURE_BSDF_REFLECTION_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID) +#define CLOSURE_IS_BSDF_GLOSSY(type) ((type >= CLOSURE_BSDF_REFLECTION_ID && type <= CLOSURE_BSDF_HAIR_REFLECTION_ID )|| (type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID)) #define CLOSURE_IS_BSDF_TRANSMISSION(type) (type >= CLOSURE_BSDF_TRANSLUCENT_ID && type <= CLOSURE_BSDF_HAIR_TRANSMISSION_ID) #define CLOSURE_IS_BSDF_BSSRDF(type) (type == CLOSURE_BSDF_BSSRDF_ID || type == CLOSURE_BSDF_BSSRDF_PRINCIPLED_ID) #define CLOSURE_IS_BSDF_SINGULAR(type) (type == CLOSURE_BSDF_REFLECTION_ID || \ diff --git a/intern/cycles/kernel/svm/svm_voronoi.h b/intern/cycles/kernel/svm/svm_voronoi.h index e5e350bf76a..75af910d940 100644 --- a/intern/cycles/kernel/svm/svm_voronoi.h +++ b/intern/cycles/kernel/svm/svm_voronoi.h @@ -52,7 +52,7 @@ ccl_device void voronoi_neighbors(float3 p, NodeVoronoiDistanceMetric distance, case NODE_VORONOI_CHEBYCHEV: d = max3(fabs(vp - p)); break; - case NODE_VORONOI_MINKOWSKI: + case NODE_VORONOI_MINKOWSKI: { float3 n = fabs(vp - p); if(e == 0.5f) { d = sqr(reduce_add(sqrt(n))); @@ -61,6 +61,7 @@ ccl_device void voronoi_neighbors(float3 p, NodeVoronoiDistanceMetric distance, d = powf(reduce_add(pow3(n, e)), 1.0f/e); } break; + } } /* To keep the shortest four distances and associated points we have to keep them in sorted order. */ diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index b7248354abd..7d2220f37f9 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -33,6 +33,7 @@ set(SRC session.cpp shader.cpp sobol.cpp + stats.cpp svm.cpp tables.cpp tile.cpp @@ -60,6 +61,7 @@ set(SRC_HEADERS session.h shader.h sobol.h + stats.h svm.h tables.h tile.h diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index 78a2039c423..3a9e2981418 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -1091,6 +1091,9 @@ int ShaderGraph::get_num_closures() else if(CLOSURE_IS_VOLUME(closure_type)) { num_closures += VOLUME_STACK_SIZE; } + else if(closure_type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) { + num_closures += 4; + } else { ++num_closures; } diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index fa280fec01f..2865b0e5e97 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -17,6 +17,7 @@ #include "device/device.h" #include "render/image.h" #include "render/scene.h" +#include "render/stats.h" #include "util/util_foreach.h" #include "util/util_logging.h" @@ -30,20 +31,58 @@ CCL_NAMESPACE_BEGIN +namespace { + /* Some helpers to silence warning in templated function. */ -static bool isfinite(uchar /*value*/) +bool isfinite(uchar /*value*/) { - return false; + return true; } -static bool isfinite(half /*value*/) +bool isfinite(half /*value*/) { - return false; + return true; } -static bool isfinite(uint16_t /*value*/) +bool isfinite(uint16_t /*value*/) { - return false; + return true; +} + +/* The lower three bits of a device texture slot number indicate its type. + * These functions convert the slot ids from ImageManager "images" ones + * to device ones and vice verse. + */ +int type_index_to_flattened_slot(int slot, ImageDataType type) +{ + return (slot << IMAGE_DATA_TYPE_SHIFT) | (type); } +int flattened_slot_to_type_index(int flat_slot, ImageDataType *type) +{ + *type = (ImageDataType)(flat_slot & IMAGE_DATA_TYPE_MASK); + return flat_slot >> IMAGE_DATA_TYPE_SHIFT; +} + +const char* name_from_type(ImageDataType type) +{ + switch(type) { + case IMAGE_DATA_TYPE_FLOAT4: return "float4"; + case IMAGE_DATA_TYPE_BYTE4: return "byte4"; + case IMAGE_DATA_TYPE_HALF4: return "half4"; + case IMAGE_DATA_TYPE_FLOAT: return "float"; + case IMAGE_DATA_TYPE_BYTE: return "byte"; + case IMAGE_DATA_TYPE_HALF: return "half"; + case IMAGE_DATA_TYPE_USHORT4: return "ushort4"; + case IMAGE_DATA_TYPE_USHORT: return "ushort"; + case IMAGE_DATA_NUM_TYPES: + assert(!"System enumerator type, should never be used"); + return ""; + } + assert(!"Unhandled image data type"); + return ""; +} + +} // namespace + ImageManager::ImageManager(const DeviceInfo& info) { need_update = true; @@ -90,12 +129,12 @@ bool ImageManager::set_animation_frame_update(int frame) device_memory *ImageManager::image_memory(int flat_slot) { - ImageDataType type; - int slot = flattened_slot_to_type_index(flat_slot, &type); + ImageDataType type; + int slot = flattened_slot_to_type_index(flat_slot, &type); - Image *img = images[type][slot]; + Image *img = images[type][slot]; - return img->mem; + return img->mem; } bool ImageManager::get_image_metadata(int flat_slot, @@ -133,10 +172,12 @@ bool ImageManager::get_image_metadata(const string& filename, if(metadata.is_float) { metadata.is_linear = true; - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT; + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 + : IMAGE_DATA_TYPE_FLOAT; } else { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE; + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 + : IMAGE_DATA_TYPE_BYTE; } return true; @@ -148,7 +189,8 @@ bool ImageManager::get_image_metadata(const string& filename, return false; } if(path_is_directory(filename)) { - VLOG(1) << "File '" << filename << "' is a directory, can't use as image."; + VLOG(1) << "File '" << filename + << "' is a directory, can't use as image."; return false; } @@ -211,16 +253,20 @@ bool ImageManager::get_image_metadata(const string& filename, metadata.channels = spec.nchannels; if(metadata.is_half) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF; + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_HALF4 + : IMAGE_DATA_TYPE_HALF; } else if(metadata.is_float) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT; + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 + : IMAGE_DATA_TYPE_FLOAT; } else if(spec.format == TypeDesc::USHORT) { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 : IMAGE_DATA_TYPE_USHORT; + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_USHORT4 + : IMAGE_DATA_TYPE_USHORT; } else { - metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 : IMAGE_DATA_TYPE_BYTE; + metadata.type = (metadata.channels > 1) ? IMAGE_DATA_TYPE_BYTE4 + : IMAGE_DATA_TYPE_BYTE; } in->close(); @@ -229,50 +275,6 @@ bool ImageManager::get_image_metadata(const string& filename, return true; } -int ImageManager::max_flattened_slot(ImageDataType type) -{ - if(tex_num_images[type] == 0) { - /* No textures for the type, no slots needs allocation. */ - return 0; - } - return type_index_to_flattened_slot(tex_num_images[type], type); -} - -/* The lower three bits of a device texture slot number indicate its type. - * These functions convert the slot ids from ImageManager "images" ones - * to device ones and vice verse. - */ -int ImageManager::type_index_to_flattened_slot(int slot, ImageDataType type) -{ - return (slot << IMAGE_DATA_TYPE_SHIFT) | (type); -} - -int ImageManager::flattened_slot_to_type_index(int flat_slot, ImageDataType *type) -{ - *type = (ImageDataType)(flat_slot & IMAGE_DATA_TYPE_MASK); - return flat_slot >> IMAGE_DATA_TYPE_SHIFT; -} - -string ImageManager::name_from_type(int type) -{ - if(type == IMAGE_DATA_TYPE_FLOAT4) - return "float4"; - else if(type == IMAGE_DATA_TYPE_FLOAT) - return "float"; - else if(type == IMAGE_DATA_TYPE_BYTE) - return "byte"; - else if(type == IMAGE_DATA_TYPE_HALF4) - return "half4"; - else if(type == IMAGE_DATA_TYPE_HALF) - return "half"; - else if(type == IMAGE_DATA_TYPE_USHORT) - return "ushort"; - else if(type == IMAGE_DATA_TYPE_USHORT4) - return "ushort4"; - else - return "byte4"; -} - static bool image_equals(ImageManager::Image *image, const string& filename, void *builtin_data, @@ -344,14 +346,16 @@ int ImageManager::add_image(const string& filename, } /* Count if we're over the limit. - * Very unlikely, since max_num_images is insanely big. But better safe than sorry. */ + * Very unlikely, since max_num_images is insanely big. But better safe + * than sorry. + */ int tex_count = 0; for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { tex_count += tex_num_images[type]; } if(tex_count > max_num_images) { - printf("ImageManager::add_image: Reached image limit (%d), skipping '%s'\n", - max_num_images, filename.c_str()); + printf("ImageManager::add_image: Reached image limit (%d), " + "skipping '%s'\n", max_num_images, filename.c_str()); return -1; } @@ -508,7 +512,6 @@ bool ImageManager::file_load_image(Image *img, int texture_limit, device_vector<DeviceType>& tex_img) { - const StorageType alpha_one = (FileFormat == TypeDesc::UINT8)? 255 : 1; ImageInput *in = NULL; if(!file_load_image_generic(img, &in)) { return false; @@ -601,13 +604,19 @@ bool ImageManager::file_load_image(Image *img, type == IMAGE_DATA_TYPE_BYTE4 || type == IMAGE_DATA_TYPE_USHORT4); if(is_rgba) { + const StorageType one = util_image_cast_from_float<StorageType>(1.0f); + if(cmyk) { /* CMYK */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255; - pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255; - pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255; - pixels[i*4+3] = alpha_one; + float c = util_image_cast_to_float(pixels[i*4+0]); + float m = util_image_cast_to_float(pixels[i*4+1]); + float y = util_image_cast_to_float(pixels[i*4+2]); + float k = util_image_cast_to_float(pixels[i*4+3]); + pixels[i*4+0] = util_image_cast_from_float<StorageType>((1.0f - c) * (1.0f - k)); + pixels[i*4+1] = util_image_cast_from_float<StorageType>((1.0f - m) * (1.0f - k)); + pixels[i*4+2] = util_image_cast_from_float<StorageType>((1.0f - y) * (1.0f - k)); + pixels[i*4+3] = one; } } else if(components == 2) { @@ -622,7 +631,7 @@ bool ImageManager::file_load_image(Image *img, else if(components == 3) { /* RGB */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = alpha_one; + pixels[i*4+3] = one; pixels[i*4+2] = pixels[i*3+2]; pixels[i*4+1] = pixels[i*3+1]; pixels[i*4+0] = pixels[i*3+0]; @@ -631,7 +640,7 @@ bool ImageManager::file_load_image(Image *img, else if(components == 1) { /* grayscale */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = alpha_one; + pixels[i*4+3] = one; pixels[i*4+2] = pixels[i]; pixels[i*4+1] = pixels[i]; pixels[i*4+0] = pixels[i]; @@ -639,7 +648,7 @@ bool ImageManager::file_load_image(Image *img, } if(img->use_alpha == false) { for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = alpha_one; + pixels[i*4+3] = one; } } } @@ -727,7 +736,8 @@ void ImageManager::device_load_image(Device *device, /* Slot assignment */ int flat_slot = type_index_to_flattened_slot(slot, type); - img->mem_name = string_printf("__tex_image_%s_%03d", name_from_type(type).c_str(), flat_slot); + img->mem_name = string_printf("__tex_image_%s_%03d", + name_from_type(type), flat_slot); /* Free previous texture in slot. */ if(img->mem) { @@ -871,7 +881,7 @@ void ImageManager::device_load_image(Device *device, thread_scoped_lock device_lock(device_mutex); uint16_t *pixels = (uint16_t*)tex_img->alloc(1, 1); - pixels[0] = TEX_IMAGE_MISSING_R; + pixels[0] = (TEX_IMAGE_MISSING_R * 65535); } img->mem = tex_img; @@ -893,10 +903,10 @@ void ImageManager::device_load_image(Device *device, thread_scoped_lock device_lock(device_mutex); uint16_t *pixels = (uint16_t*)tex_img->alloc(1, 1); - pixels[0] = TEX_IMAGE_MISSING_R; - pixels[1] = TEX_IMAGE_MISSING_G; - pixels[2] = TEX_IMAGE_MISSING_B; - pixels[3] = TEX_IMAGE_MISSING_A; + pixels[0] = (TEX_IMAGE_MISSING_R * 65535); + pixels[1] = (TEX_IMAGE_MISSING_G * 65535); + pixels[2] = (TEX_IMAGE_MISSING_B * 65535); + pixels[3] = (TEX_IMAGE_MISSING_A * 65535); } img->mem = tex_img; @@ -1066,4 +1076,15 @@ void ImageManager::device_free(Device *device) } } +void ImageManager::collect_statistics(RenderStats *stats) +{ + for(int type = 0; type < IMAGE_DATA_NUM_TYPES; type++) { + foreach(const Image *image, images[type]) { + stats->image.textures.add_entry( + NamedSizeEntry(path_filename(image->filename), + image->mem->memory_size())); + } + } +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index c9667fb77a9..0bf06c322d0 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -29,6 +29,7 @@ CCL_NAMESPACE_BEGIN class Device; class Progress; +class RenderStats; class Scene; class ImageMetaData { @@ -93,6 +94,8 @@ public: device_memory *image_memory(int flat_slot); + void collect_statistics(RenderStats *stats); + bool need_update; /* NOTE: Here pixels_size is a size of storage, which equals to @@ -153,16 +156,11 @@ private: int texture_limit, device_vector<DeviceType>& tex_img); - int max_flattened_slot(ImageDataType type); - int type_index_to_flattened_slot(int slot, ImageDataType type); - int flattened_slot_to_type_index(int flat_slot, ImageDataType *type); - string name_from_type(int type); - void device_load_image(Device *device, Scene *scene, ImageDataType type, int slot, - Progress *progess); + Progress *progress); void device_free_image(Device *device, ImageDataType type, int slot); diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 7a9d604244d..ade575a52d6 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -27,6 +27,7 @@ #include "render/nodes.h" #include "render/object.h" #include "render/scene.h" +#include "render/stats.h" #include "kernel/osl/osl_globals.h" @@ -2015,8 +2016,8 @@ void MeshManager::device_update_displacement_images(Device *device, } void MeshManager::device_update_volume_images(Device *device, - Scene *scene, - Progress& progress) + Scene *scene, + Progress& progress) { progress.set_status("Updating Volume Images"); TaskPool pool; @@ -2043,11 +2044,11 @@ void MeshManager::device_update_volume_images(Device *device, foreach(int slot, volume_images) { pool.push(function_bind(&ImageManager::device_update_slot, - image_manager, - device, - scene, - slot, - &progress)); + image_manager, + device, + scene, + slot, + &progress)); } pool.wait_work(); } @@ -2276,6 +2277,15 @@ void MeshManager::tag_update(Scene *scene) scene->object_manager->need_update = true; } +void MeshManager::collect_statistics(const Scene *scene, RenderStats *stats) +{ + foreach(Mesh *mesh, scene->meshes) { + stats->mesh.geometry.add_entry( + NamedSizeEntry(string(mesh->name.c_str()), + mesh->get_total_size_in_bytes())); + } +} + bool Mesh::need_attribute(Scene *scene, AttributeStandard std) { if(std == ATTR_STD_NONE) diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index e7dc1c8e5cf..444f03a3664 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -38,6 +38,7 @@ class Device; class DeviceScene; class Mesh; class Progress; +class RenderStats; class Scene; class SceneParams; class AttributeRequest; @@ -351,6 +352,8 @@ public: void create_volume_mesh(Scene *scene, Mesh *mesh, Progress &progress); + void collect_statistics(const Scene *scene, RenderStats *stats); + protected: /* Calculate verts/triangles/curves offsets in global arrays. */ void mesh_calc_offset(Scene *scene); @@ -381,8 +384,8 @@ protected: Progress& progress); void device_update_volume_images(Device *device, - Scene *scene, - Progress& progress); + Scene *scene, + Progress& progress); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh_volume.cpp b/intern/cycles/render/mesh_volume.cpp index d1c49b456ff..3ee4124ba0f 100644 --- a/intern/cycles/render/mesh_volume.cpp +++ b/intern/cycles/render/mesh_volume.cpp @@ -87,23 +87,31 @@ const float3 quads_normals[6] = { make_float3(0.0f, 0.0f, 1.0f), }; -static void create_quad(int3 corners[8], vector<int3> &vertices, vector<QuadData> &quads, int face_index) +static int add_vertex(int3 v, vector<int3> &vertices, int3 res, unordered_map<size_t, int> &used_verts) { - size_t vertex_offset = vertices.size(); + size_t vert_key = v.x + v.y * (res.x+1) + v.z * (res.x+1)*(res.y+1); + unordered_map<size_t, int>::iterator it = used_verts.find(vert_key); + if(it != used_verts.end()) { + return it->second; + } + + int vertex_offset = vertices.size(); + used_verts[vert_key] = vertex_offset; + vertices.push_back(v); + return vertex_offset; +} + +static void create_quad(int3 corners[8], vector<int3> &vertices, vector<QuadData> &quads, int3 res, unordered_map<size_t, int> &used_verts, int face_index) +{ QuadData quad; - quad.v0 = vertex_offset + 0; - quad.v1 = vertex_offset + 1; - quad.v2 = vertex_offset + 2; - quad.v3 = vertex_offset + 3; + quad.v0 = add_vertex(corners[quads_indices[face_index][0]], vertices, res, used_verts); + quad.v1 = add_vertex(corners[quads_indices[face_index][1]], vertices, res, used_verts); + quad.v2 = add_vertex(corners[quads_indices[face_index][2]], vertices, res, used_verts); + quad.v3 = add_vertex(corners[quads_indices[face_index][3]], vertices, res, used_verts); quad.normal = quads_normals[face_index]; quads.push_back(quad); - - vertices.push_back(corners[quads_indices[face_index][0]]); - vertices.push_back(corners[quads_indices[face_index][1]]); - vertices.push_back(corners[quads_indices[face_index][2]]); - vertices.push_back(corners[quads_indices[face_index][3]]); } struct VolumeParams { @@ -159,9 +167,6 @@ private: void generate_vertices_and_quads(vector<int3> &vertices_is, vector<QuadData> &quads); - void deduplicate_vertices(vector<int3> &vertices, - vector<QuadData> &quads); - void convert_object_space(const vector<int3> &vertices, vector<float3> &out_vertices); @@ -234,8 +239,6 @@ void VolumeMeshBuilder::create_mesh(vector<float3> &vertices, generate_vertices_and_quads(vertices_is, quads); - deduplicate_vertices(vertices_is, quads); - convert_object_space(vertices_is, vertices); convert_quads_to_tris(quads, indices, face_normals); @@ -245,10 +248,7 @@ void VolumeMeshBuilder::generate_vertices_and_quads( vector<ccl::int3> &vertices_is, vector<QuadData> &quads) { - /* Overallocation, we could count the number of quads and vertices to create - * in a pre-pass if memory becomes an issue. */ - vertices_is.reserve(number_of_nodes*8); - quads.reserve(number_of_nodes*6); + unordered_map<size_t, int> used_verts; for(int z = 0; z < res.z; ++z) { for(int y = 0; y < res.y; ++y) { @@ -283,77 +283,38 @@ void VolumeMeshBuilder::generate_vertices_and_quads( voxel_index = compute_voxel_index(res, x - 1, y, z); if(voxel_index == -1 || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, QUAD_X_MIN); + create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MIN); } voxel_index = compute_voxel_index(res, x + 1, y, z); if(voxel_index == -1 || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, QUAD_X_MAX); + create_quad(corners, vertices_is, quads, res, used_verts, QUAD_X_MAX); } voxel_index = compute_voxel_index(res, x, y - 1, z); if(voxel_index == -1 || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, QUAD_Y_MIN); + create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MIN); } voxel_index = compute_voxel_index(res, x, y + 1, z); if(voxel_index == -1 || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, QUAD_Y_MAX); + create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Y_MAX); } voxel_index = compute_voxel_index(res, x, y, z - 1); if(voxel_index == -1 || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, QUAD_Z_MIN); + create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MIN); } voxel_index = compute_voxel_index(res, x, y, z + 1); if(voxel_index == -1 || grid[voxel_index] == 0) { - create_quad(corners, vertices_is, quads, QUAD_Z_MAX); + create_quad(corners, vertices_is, quads, res, used_verts, QUAD_Z_MAX); } } } } } -void VolumeMeshBuilder::deduplicate_vertices(vector<int3> &vertices, - vector<QuadData> &quads) -{ - vector<int3> sorted_vertices = vertices; - std::sort(sorted_vertices.begin(), sorted_vertices.end()); - vector<int3>::iterator it = std::unique(sorted_vertices.begin(), sorted_vertices.end()); - sorted_vertices.resize(std::distance(sorted_vertices.begin(), it)); - - vector<QuadData> new_quads = quads; - - for(size_t i = 0; i < vertices.size(); ++i) { - for(size_t j = 0; j < sorted_vertices.size(); ++j) { - if(vertices[i] != sorted_vertices[j]) { - continue; - } - - for(int k = 0; k < quads.size(); ++k) { - if(quads[k].v0 == i) { - new_quads[k].v0 = j; - } - else if(quads[k].v1 == i) { - new_quads[k].v1 = j; - } - else if(quads[k].v2 == i) { - new_quads[k].v2 = j; - } - else if(quads[k].v3 == i) { - new_quads[k].v3 = j; - } - } - - break; - } - } - - vertices = sorted_vertices; - quads = new_quads; -} - void VolumeMeshBuilder::convert_object_space(const vector<int3> &vertices, vector<float3> &out_vertices) { diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index e6bb341d1b8..cce851612db 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -3089,6 +3089,139 @@ void PrincipledVolumeNode::compile(OSLCompiler& compiler) compiler.add(this, "node_principled_volume"); } +/* Principled Hair BSDF Closure */ + +NODE_DEFINE(PrincipledHairBsdfNode) +{ + NodeType* type = NodeType::add("principled_hair_bsdf", create, NodeType::SHADER); + + /* Color parametrization specified as enum. */ + static NodeEnum parametrization_enum; + parametrization_enum.insert("Direct coloring", NODE_PRINCIPLED_HAIR_REFLECTANCE); + parametrization_enum.insert("Melanin concentration", NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); + parametrization_enum.insert("Absorption coefficient", NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION); + SOCKET_ENUM(parametrization, "Parametrization", parametrization_enum, NODE_PRINCIPLED_HAIR_REFLECTANCE); + + /* Initialize sockets to their default values. */ + SOCKET_IN_COLOR(color, "Color", make_float3(0.017513f, 0.005763f, 0.002059f)); + SOCKET_IN_FLOAT(melanin, "Melanin", 0.8f); + SOCKET_IN_FLOAT(melanin_redness, "Melanin Redness", 1.0f); + SOCKET_IN_COLOR(tint, "Tint", make_float3(1.f, 1.f, 1.f)); + SOCKET_IN_VECTOR(absorption_coefficient, "Absorption Coefficient", make_float3(0.245531f, 0.52f, 1.365f), SocketType::VECTOR); + + SOCKET_IN_FLOAT(offset, "Offset", 2.f*M_PI_F/180.f); + SOCKET_IN_FLOAT(roughness, "Roughness", 0.3f); + SOCKET_IN_FLOAT(radial_roughness, "Radial Roughness", 0.3f); + SOCKET_IN_FLOAT(coat, "Coat", 0.0f); + SOCKET_IN_FLOAT(ior, "IOR", 1.55f); + + SOCKET_IN_FLOAT(random_roughness, "Random Roughness", 0.0f); + SOCKET_IN_FLOAT(random_color, "Random Color", 0.0f); + SOCKET_IN_FLOAT(random, "Random", 0.0f); + + SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL); + SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL); + + SOCKET_OUT_CLOSURE(BSDF, "BSDF"); + + return type; +} + +PrincipledHairBsdfNode::PrincipledHairBsdfNode() +: BsdfBaseNode(node_type) +{ + closure = CLOSURE_BSDF_HAIR_PRINCIPLED_ID; +} + +/* Enable retrieving Hair Info -> Random if Random isn't linked. */ +void PrincipledHairBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes) +{ + if(!input("Random")->link) { + attributes->add(ATTR_STD_CURVE_RANDOM); + } + ShaderNode::attributes(shader, attributes); +} + +/* Prepares the input data for the SVM shader. */ +void PrincipledHairBsdfNode::compile(SVMCompiler& compiler) +{ + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, make_float3(1.0f, 1.0f, 1.0f)); + + ShaderInput *roughness_in = input("Roughness"); + ShaderInput *radial_roughness_in = input("Radial Roughness"); + ShaderInput *random_roughness_in = input("Random Roughness"); + ShaderInput *offset_in = input("Offset"); + ShaderInput *coat_in = input("Coat"); + ShaderInput *ior_in = input("IOR"); + ShaderInput *melanin_in = input("Melanin"); + ShaderInput *melanin_redness_in = input("Melanin Redness"); + ShaderInput *random_color_in = input("Random Color"); + + int color_ofs = compiler.stack_assign(input("Color")); + int tint_ofs = compiler.stack_assign(input("Tint")); + int absorption_coefficient_ofs = compiler.stack_assign(input("Absorption Coefficient")); + + ShaderInput *random_in = input("Random"); + int attr_random = random_in->link ? SVM_STACK_INVALID : compiler.attribute(ATTR_STD_CURVE_RANDOM); + + /* Encode all parameters into data nodes. */ + compiler.add_node(NODE_CLOSURE_BSDF, + /* Socket IDs can be packed 4 at a time into a single data packet */ + compiler.encode_uchar4(closure, + compiler.stack_assign_if_linked(roughness_in), + compiler.stack_assign_if_linked(radial_roughness_in), + compiler.closure_mix_weight_offset()), + /* The rest are stored as unsigned integers */ + __float_as_uint(roughness), + __float_as_uint(radial_roughness)); + + compiler.add_node(compiler.stack_assign_if_linked(input("Normal")), + compiler.encode_uchar4( + compiler.stack_assign_if_linked(offset_in), + compiler.stack_assign_if_linked(ior_in), + color_ofs, + parametrization), + __float_as_uint(offset), + __float_as_uint(ior)); + + compiler.add_node( + compiler.encode_uchar4( + compiler.stack_assign_if_linked(coat_in), + compiler.stack_assign_if_linked(melanin_in), + compiler.stack_assign_if_linked(melanin_redness_in), + absorption_coefficient_ofs), + __float_as_uint(coat), + __float_as_uint(melanin), + __float_as_uint(melanin_redness)); + + compiler.add_node( + compiler.encode_uchar4( + tint_ofs, + compiler.stack_assign_if_linked(random_in), + compiler.stack_assign_if_linked(random_color_in), + compiler.stack_assign_if_linked(random_roughness_in)), + __float_as_uint(random), + __float_as_uint(random_color), + __float_as_uint(random_roughness)); + + compiler.add_node( + compiler.encode_uchar4( + SVM_STACK_INVALID, + SVM_STACK_INVALID, + SVM_STACK_INVALID, + SVM_STACK_INVALID), + attr_random, + SVM_STACK_INVALID, + SVM_STACK_INVALID); +} + +/* Prepares the input data for the OSL shader. */ +void PrincipledHairBsdfNode::compile(OSLCompiler& compiler) +{ + compiler.parameter(this, "parametrization"); + compiler.add(this, "node_principled_hair_bsdf"); +} + /* Hair BSDF Closure */ NODE_DEFINE(HairBsdfNode) diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index fd043ce5161..c2cf13ad020 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -610,6 +610,45 @@ public: float temperature; }; +/* Interface between the I/O sockets and the SVM/OSL backend. */ +class PrincipledHairBsdfNode : public BsdfBaseNode { +public: + SHADER_NODE_CLASS(PrincipledHairBsdfNode) + void attributes(Shader *shader, AttributeRequestSet *attributes); + + /* Longitudinal roughness. */ + float roughness; + /* Azimuthal roughness. */ + float radial_roughness; + /* Randomization factor for roughnesses. */ + float random_roughness; + /* Longitudinal roughness factor for only the diffuse bounce (shiny undercoat). */ + float coat; + /* Index of reflection. */ + float ior; + /* Cuticle tilt angle. */ + float offset; + /* Direct coloring's color. */ + float3 color; + /* Melanin concentration. */ + float melanin; + /* Melanin redness ratio. */ + float melanin_redness; + /* Dye color. */ + float3 tint; + /* Randomization factor for melanin quantities. */ + float random_color; + /* Absorption coefficient (unfiltered). */ + float3 absorption_coefficient; + + float3 normal; + float surface_mix_weight; + /* If linked, here will be the given random number. */ + float random; + /* Selected coloring parametrization. */ + NodePrincipledHairParametrization parametrization; +}; + class HairBsdfNode : public BsdfNode { public: SHADER_NODE_CLASS(HairBsdfNode) diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index 1d65ef65980..9f93fed139c 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -379,4 +379,10 @@ void Scene::device_free() free_memory(false); } +void Scene::collect_statistics(RenderStats *stats) +{ + mesh_manager->collect_statistics(this, stats); + image_manager->collect_statistics(stats); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 713eba623b1..dd8069537eb 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -56,6 +56,7 @@ class ShaderManager; class Progress; class BakeManager; class BakeData; +class RenderStats; /* Scene Device Data */ @@ -255,6 +256,8 @@ public: void reset(); void device_free(); + void collect_statistics(RenderStats *stats); + protected: /* Check if some heavy data worth logging was updated. * Mainly used to suppress extra annoying logging. diff --git a/intern/cycles/render/stats.cpp b/intern/cycles/render/stats.cpp new file mode 100644 index 00000000000..101d33fcf65 --- /dev/null +++ b/intern/cycles/render/stats.cpp @@ -0,0 +1,119 @@ +/* + * Copyright 2011-2018 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 "render/stats.h" +#include "util/util_algorithm.h" +#include "util/util_foreach.h" +#include "util/util_string.h" + +CCL_NAMESPACE_BEGIN + +static int kIndentNumSpaces = 2; + +/* Named size entry. */ + +namespace { + +bool namedSizeEntryComparator(const NamedSizeEntry& a, const NamedSizeEntry& b) +{ + /* We sort in descending order. */ + return a.size > b.size; +} + +} // namespace + +NamedSizeEntry::NamedSizeEntry() + : name(""), + size(0) { +} + +NamedSizeEntry::NamedSizeEntry(const string& name, size_t size) + : name(name), + size(size) { +} + +/* Named size statistics. */ + +NamedSizeStats::NamedSizeStats() + : total_size(0) { +} + +void NamedSizeStats::add_entry(const NamedSizeEntry& entry) { + total_size += entry.size; + entries.push_back(entry); +} + +string NamedSizeStats::full_report(int indent_level) +{ + const string indent(indent_level * kIndentNumSpaces, ' '); + const string double_indent = indent + indent; + string result = ""; + result += string_printf("%sTotal memory: %s (%s)\n", + indent.c_str(), + string_human_readable_size(total_size).c_str(), + string_human_readable_number(total_size).c_str()); + sort(entries.begin(), entries.end(), namedSizeEntryComparator); + foreach(const NamedSizeEntry& entry, entries) { + result += string_printf( + "%s%-32s %s (%s)\n", + double_indent.c_str(), + entry.name.c_str(), + string_human_readable_size(entry.size).c_str(), + string_human_readable_number(entry.size).c_str()); + } + return result; +} + +/* Mesh statistics. */ + +MeshStats::MeshStats() { +} + +string MeshStats::full_report(int indent_level) +{ + const string indent(indent_level * kIndentNumSpaces, ' '); + string result = ""; + result += indent + "Geometry:\n" + geometry.full_report(indent_level + 1); + return result; +} + +/* Image statistics. */ + +ImageStats::ImageStats() { +} + +string ImageStats::full_report(int indent_level) +{ + const string indent(indent_level * kIndentNumSpaces, ' '); + string result = ""; + result += indent + "Textures:\n" + textures.full_report(indent_level + 1); + return result; +} + +/* Overall statistics. */ + +RenderStats::RenderStats() { +} + +string RenderStats::full_report() +{ + string result = ""; + result += "Mesh statistics:\n" + mesh.full_report(1); + result += "Image statistics:\n" + image.full_report(1); + return result; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/render/stats.h b/intern/cycles/render/stats.h new file mode 100644 index 00000000000..72d5f1dd93d --- /dev/null +++ b/intern/cycles/render/stats.h @@ -0,0 +1,104 @@ +/* + * Copyright 2011-2018 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. + */ + +#ifndef __RENDER_STATS_H__ +#define __RENDER_STATS_H__ + +#include "util/util_string.h" +#include "util/util_vector.h" + +CCL_NAMESPACE_BEGIN + +/* Named statistics entry, which corresponds to a size. There is no real + * semantic around the units of size, it just should be the same for all + * entries. + * + * This is a generic entry foi all size-related statistics, which helps + * avoiding duplicating code for things like sorting. + */ +class NamedSizeEntry { +public: + NamedSizeEntry(); + NamedSizeEntry(const string& name, size_t size); + + string name; + size_t size; +}; + +/* Container of named size entries. Used, for example, to store per-mesh memory + * usage statistics. But also keeps track of overall memory usage of the + * container. + */ +class NamedSizeStats { +public: + NamedSizeStats(); + + /* Add entry to the statistics. */ + void add_entry(const NamedSizeEntry& entry); + + /* Generate full human-readable report. */ + string full_report(int indent_level = 0); + + /* Total size of all entries. */ + size_t total_size; + + /* NOTE: Is fine to read directly, but for adding use add_entry(), which + * makes sure all accumulating values are properly updated. + */ + vector<NamedSizeEntry> entries; +}; + +/* Statistics about mesh in the render database. */ +class MeshStats { +public: + MeshStats(); + + /* Generate full human-readable report. */ + string full_report(int indent_level = 0); + + /* Input geometry statistics, this is what is coming as an input to render + * from. say, Blender. This does not include runtime or engine specific + * memory like BVH. + */ + NamedSizeStats geometry; +}; + +/* Statistics about images held in memory. */ +class ImageStats { +public: + ImageStats(); + + /* Generate full human-readable report. */ + string full_report(int indent_level = 0); + + NamedSizeStats textures; +}; + +/* Render process statistics. */ +class RenderStats { +public: + RenderStats(); + + /* Return full report as string. */ + string full_report(); + + MeshStats mesh; + ImageStats image; +}; + +CCL_NAMESPACE_END + +#endif /* __RENDER_STATS_H__ */ diff --git a/intern/cycles/util/util_defines.h b/intern/cycles/util/util_defines.h index d994d4e08f4..8bce4aca699 100644 --- a/intern/cycles/util/util_defines.h +++ b/intern/cycles/util/util_defines.h @@ -87,12 +87,8 @@ # define UNLIKELY(x) (x) #endif -#if defined(__cplusplus) && ((__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1800)) -# define HAS_CPP11_FEATURES -#endif - #if defined(__GNUC__) || defined(__clang__) -# if defined(HAS_CPP11_FEATURES) +# if defined(__cplusplus) /* Some magic to be sure we don't have reference in the type. */ template<typename T> static inline T decltype_helper(T x) { return x; } # define TYPEOF(x) decltype(decltype_helper(x)) diff --git a/intern/cycles/util/util_foreach.h b/intern/cycles/util/util_foreach.h index 03fcefc67b9..2a74ff0a55d 100644 --- a/intern/cycles/util/util_foreach.h +++ b/intern/cycles/util/util_foreach.h @@ -17,13 +17,8 @@ #ifndef __UTIL_FOREACH_H__ #define __UTIL_FOREACH_H__ -/* Use Boost to get nice foreach() loops for STL data structures. */ +/* Nice foreach() loops for STL data structures. */ -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) -# define foreach(x, y) for(x : y) -#else -# include <boost/foreach.hpp> -# define foreach BOOST_FOREACH -#endif +#define foreach(x, y) for(x : y) #endif /* __UTIL_FOREACH_H__ */ diff --git a/intern/cycles/util/util_function.h b/intern/cycles/util/util_function.h index 958f8b4008c..f3cc00329ad 100644 --- a/intern/cycles/util/util_function.h +++ b/intern/cycles/util/util_function.h @@ -17,18 +17,12 @@ #ifndef __UTIL_FUNCTION_H__ #define __UTIL_FUNCTION_H__ -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) -# include <functional> -#else -# include <boost/bind.hpp> -# include <boost/function.hpp> -#endif +#include <functional> CCL_NAMESPACE_BEGIN -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) -# define function_bind std::bind -# define function_null nullptr +#define function_bind std::bind +#define function_null nullptr using std::function; using std::placeholders::_1; using std::placeholders::_2; @@ -39,11 +33,7 @@ using std::placeholders::_6; using std::placeholders::_7; using std::placeholders::_8; using std::placeholders::_9; -#else -using boost::function; -# define function_bind boost::bind -# define function_null NULL -#endif + CCL_NAMESPACE_END #endif /* __UTIL_FUNCTION_H__ */ diff --git a/intern/cycles/util/util_half.h b/intern/cycles/util/util_half.h index 58f3f903619..53b7f2472bd 100644 --- a/intern/cycles/util/util_half.h +++ b/intern/cycles/util/util_half.h @@ -42,7 +42,7 @@ public: half() : v(0) {} half(const unsigned short& i) : v(i) {} operator unsigned short() { return v; } - half & operator =(const unsigned short& i) { v = i; return *this; } + half& operator =(const unsigned short& i) { v = i; return *this; } private: unsigned short v; }; diff --git a/intern/cycles/util/util_image.h b/intern/cycles/util/util_image.h index 18876841b5b..85bdb0d8050 100644 --- a/intern/cycles/util/util_image.h +++ b/intern/cycles/util/util_image.h @@ -38,6 +38,68 @@ void util_image_resize_pixels(const vector<T>& input_pixels, size_t *output_height, size_t *output_depth); +/* Cast input pixel from unknown storage to float. */ +template<typename T> +inline float util_image_cast_to_float(T value); + +template<> +inline float util_image_cast_to_float(float value) +{ + return value; +} +template<> +inline float util_image_cast_to_float(uchar value) +{ + return (float)value / 255.0f; +} +template<> +inline float util_image_cast_to_float(uint16_t value) +{ + return (float)value / 65535.0f; +} +template<> +inline float util_image_cast_to_float(half value) +{ + return half_to_float(value); +} + +/* Cast float value to output pixel type. */ +template<typename T> +inline T util_image_cast_from_float(float value); + +template<> +inline float util_image_cast_from_float(float value) +{ + return value; +} +template<> +inline uchar util_image_cast_from_float(float value) +{ + if(value < 0.0f) { + return 0; + } + else if(value > (1.0f - 0.5f / 255.0f)) { + return 255; + } + return (uchar)((255.0f * value) + 0.5f); +} +template<> +inline uint16_t util_image_cast_from_float(float value) +{ + if(value < 0.0f) { + return 0; + } + else if(value > (1.0f - 0.5f / 65535.0f)) { + return 65535; + } + return (uint16_t)((65535.0f * value) + 0.5f); +} +template<> +inline half util_image_cast_from_float(float value) +{ + return float_to_half(value); +} + CCL_NAMESPACE_END #endif /* __UTIL_IMAGE_H__ */ diff --git a/intern/cycles/util/util_image_impl.h b/intern/cycles/util/util_image_impl.h index fb953a43ab2..5bc1c727595 100644 --- a/intern/cycles/util/util_image_impl.h +++ b/intern/cycles/util/util_image_impl.h @@ -38,68 +38,6 @@ const T *util_image_read(const vector<T>& pixels, return &pixels[index]; } -/* Cast input pixel from unknown storage to float. */ -template<typename T> -inline float cast_to_float(T value); - -template<> -inline float cast_to_float(float value) -{ - return value; -} -template<> -inline float cast_to_float(uchar value) -{ - return (float)value / 255.0f; -} -template<> -inline float cast_to_float(uint16_t value) -{ - return (float)value / 65535.0f; -} -template<> -inline float cast_to_float(half value) -{ - return half_to_float(value); -} - -/* Cast float value to output pixel type. */ -template<typename T> -inline T cast_from_float(float value); - -template<> -inline float cast_from_float(float value) -{ - return value; -} -template<> -inline uchar cast_from_float(float value) -{ - if(value < 0.0f) { - return 0; - } - else if(value > (1.0f - 0.5f / 255.0f)) { - return 255; - } - return (uchar)((255.0f * value) + 0.5f); -} -template<> -inline uint16_t cast_from_float(float value) -{ - if(value < 0.0f) { - return 0; - } - else if(value >(1.0f - 0.5f / 65535.0f)) { - return 65535; - } - return (uchar)((65535.0f * value) + 0.5f); -} -template<> -inline half cast_from_float(float value) -{ - return float_to_half(value); -} - template<typename T> void util_image_downscale_sample(const vector<T>& pixels, const size_t width, @@ -133,7 +71,7 @@ void util_image_downscale_sample(const vector<T>& pixels, components, nx, ny, nz); for(size_t k = 0; k < components; ++k) { - accum[k] += cast_to_float(pixel[k]); + accum[k] += util_image_cast_to_float(pixel[k]); } ++count; } @@ -142,7 +80,7 @@ void util_image_downscale_sample(const vector<T>& pixels, if(count != 0) { const float inv_count = 1.0f / (float)count; for(size_t k = 0; k < components; ++k) { - result[k] = cast_from_float<T>(accum[k] * inv_count); + result[k] = util_image_cast_from_float<T>(accum[k] * inv_count); } } else { diff --git a/intern/cycles/util/util_map.h b/intern/cycles/util/util_map.h index b3d887f093c..3c9288417cf 100644 --- a/intern/cycles/util/util_map.h +++ b/intern/cycles/util/util_map.h @@ -18,38 +18,13 @@ #define __UTIL_MAP_H__ #include <map> - -#if defined(CYCLES_TR1_UNORDERED_MAP) -# include <tr1/unordered_map> -#endif - -#if defined(CYCLES_STD_UNORDERED_MAP) || defined(CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) -# include <unordered_map> -#endif - -#if !defined(CYCLES_NO_UNORDERED_MAP) && !defined(CYCLES_TR1_UNORDERED_MAP) && \ - !defined(CYCLES_STD_UNORDERED_MAP) && !defined(CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT -# error One of: CYCLES_NO_UNORDERED_MAP, CYCLES_TR1_UNORDERED_MAP,\ - CYCLES_STD_UNORDERED_MAP, CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT -#endif - +#include <unordered_map> CCL_NAMESPACE_BEGIN using std::map; using std::pair; - -#if defined(CYCLES_NO_UNORDERED_MAP) -typedef std::map unordered_map; -#endif - -#if defined(CYCLES_TR1_UNORDERED_MAP) || defined(CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) -using std::tr1::unordered_map; -#endif - -#if defined(CYCLES_STD_UNORDERED_MAP) using std::unordered_map; -#endif CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 85cbd18b7ba..52aeb8d8599 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -55,6 +55,15 @@ CCL_NAMESPACE_BEGIN #ifndef M_2_PI_F # define M_2_PI_F (0.6366197723675813f) /* 2/pi */ #endif +#ifndef M_1_2PI_F +# define M_1_2PI_F (0.1591549430918953f) /* 1/(2*pi) */ +#endif +#ifndef M_SQRT_PI_8_F +# define M_SQRT_PI_8_F (0.6266570686577501f) /* sqrt(pi/8) */ +#endif +#ifndef M_LN_2PI_F +# define M_LN_2PI_F (1.8378770664093454f) /* ln(2*pi) */ +#endif /* Multiplication */ #ifndef M_2PI_F @@ -541,6 +550,16 @@ ccl_device_inline float sqr(float a) return a * a; } +ccl_device_inline float pow20(float a) +{ + return sqr(sqr(sqr(sqr(a))*a)); +} + +ccl_device_inline float pow22(float a) +{ + return sqr(a*sqr(sqr(sqr(a))*a)); +} + ccl_device_inline float beta(float x, float y) { #ifndef __KERNEL_OPENCL__ diff --git a/intern/cycles/util/util_math_float3.h b/intern/cycles/util/util_math_float3.h index 3a5a2ab2244..75265c1c9a2 100644 --- a/intern/cycles/util/util_math_float3.h +++ b/intern/cycles/util/util_math_float3.h @@ -280,11 +280,6 @@ ccl_device_inline float3 sqrt(const float3& a) #endif } -ccl_device_inline float3 pow3(const float3& a, float e) -{ - return make_float3(powf(a.x, e), powf(a.y, e), powf(a.z, e)); -} - ccl_device_inline float3 mix(const float3& a, const float3& b, float t) { return a + t*(b - a); @@ -382,6 +377,21 @@ ccl_device_inline bool isequal_float3(const float3 a, const float3 b) #endif } +ccl_device_inline float3 pow3(float3 v, float e) +{ + return make_float3(powf(v.x, e), powf(v.y, e), powf(v.z, e)); +} + +ccl_device_inline float3 exp3(float3 v) +{ + return make_float3(expf(v.x), expf(v.y), expf(v.z)); +} + +ccl_device_inline float3 log3(float3 v) +{ + return make_float3(logf(v.x), logf(v.y), logf(v.z)); +} + ccl_device_inline int3 quick_floor_to_int3(const float3 a) { #ifdef __KERNEL_SSE__ diff --git a/intern/cycles/util/util_set.h b/intern/cycles/util/util_set.h index 1d010e19996..298e1f7729a 100644 --- a/intern/cycles/util/util_set.h +++ b/intern/cycles/util/util_set.h @@ -18,24 +18,7 @@ #define __UTIL_SET_H__ #include <set> -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) -# include <unordered_set> -#else -# if defined(CYCLES_TR1_UNORDERED_MAP) -# include <tr1/unordered_set> -# endif -# if defined(CYCLES_STD_UNORDERED_MAP) || \ - defined(CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) -# include <unordered_set> -# endif -# if !defined(CYCLES_NO_UNORDERED_MAP) && \ - !defined(CYCLES_TR1_UNORDERED_MAP) && \ - !defined(CYCLES_STD_UNORDERED_MAP) && \ - !defined(CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) -# error One of: CYCLES_NO_UNORDERED_MAP, CYCLES_TR1_UNORDERED_MAP,\ - CYCLES_STD_UNORDERED_MAP, CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT -# endif -#endif +#include <unordered_set> #if defined(_MSC_VER) && (_MSC_VER >= 1900) # include <iterator> @@ -44,19 +27,8 @@ CCL_NAMESPACE_BEGIN using std::set; -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) -using std::unordered_set; -#else -# if defined(CYCLES_NO_UNORDERED_MAP) -typedef std::set unordered_set; -# endif -# if defined(CYCLES_TR1_UNORDERED_MAP) || defined(CYCLES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) -using std::tr1::unordered_set; -# endif -# if defined(CYCLES_STD_UNORDERED_MAP) using std::unordered_set; -# endif -#endif + CCL_NAMESPACE_END #endif /* __UTIL_SET_H__ */ diff --git a/intern/cycles/util/util_static_assert.h b/intern/cycles/util/util_static_assert.h index e90049254de..dc3cb3f6ecc 100644 --- a/intern/cycles/util/util_static_assert.h +++ b/intern/cycles/util/util_static_assert.h @@ -22,27 +22,7 @@ CCL_NAMESPACE_BEGIN /* TODO(sergey): In theory CUDA might work with own static assert * implementation since it's just pure C++. */ -#ifndef __KERNEL_GPU__ -# if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) -/* C++11 has built-in static_assert() */ -# elif defined(static_assert) -/* Some platforms might have static_assert() defined even tho their - * C++ support wouldn't be declared to be C++11. - */ -# else /* C++11 or MSVC2015 */ -template <bool Test> class StaticAssertFailure; -template <> class StaticAssertFailure<true> {}; -# define _static_assert_private_glue_impl(A, B) A ## B -# define _static_assert_glue(A, B) _static_assert_private_glue_impl(A, B) -# ifdef __COUNTER__ -# define static_assert(condition, message) \ - enum {_static_assert_glue(q_static_assert_result, __COUNTER__) = sizeof(StaticAssertFailure<!!(condition)>)} // NOLINT -# else /* __COUNTER__ */ -# define static_assert(condition, message) \ - enum {_static_assert_glue(q_static_assert_result, __LINE__) = sizeof(StaticAssertFailure<!!(condition)>)} // NOLINT -# endif /* __COUNTER__ */ -# endif /* C++11 or MSVC2015 */ -#else /* __KERNEL_GPU__ */ +#ifdef __KERNEL_GPU__ # ifndef static_assert # define static_assert(statement, message) # endif diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp index 995f5d3df27..47119e90a45 100644 --- a/intern/cycles/util/util_string.cpp +++ b/intern/cycles/util/util_string.cpp @@ -168,6 +168,11 @@ string string_from_bool(bool var) return "False"; } +string to_string(const char *str) +{ + return string(str); +} + /* Wide char strings helpers for Windows. */ #ifdef _WIN32 diff --git a/intern/cycles/util/util_string.h b/intern/cycles/util/util_string.h index 7dfa97335a9..3a4f4398158 100644 --- a/intern/cycles/util/util_string.h +++ b/intern/cycles/util/util_string.h @@ -29,6 +29,7 @@ using std::string; using std::stringstream; using std::ostringstream; using std::istringstream; +using std::to_string; #ifdef __GNUC__ #define PRINTF_ATTRIBUTE __attribute__((format(printf, 1, 2))) @@ -49,6 +50,7 @@ bool string_endswith(const string& s, const char *end); string string_strip(const string& s); string string_remove_trademark(const string& s); string string_from_bool(const bool var); +string to_string(const char *str); /* Wide char strings are only used on Windows to deal with non-ascii * characters in file names and such. No reason to use such strings diff --git a/intern/cycles/util/util_thread.cpp b/intern/cycles/util/util_thread.cpp index c66aa484264..16a8591a8a9 100644 --- a/intern/cycles/util/util_thread.cpp +++ b/intern/cycles/util/util_thread.cpp @@ -26,11 +26,7 @@ thread::thread(function<void(void)> run_cb, int group) joined_(false), group_(group) { -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) thread_ = std::thread(&thread::run, this); -#else - pthread_create(&pthread_id_, NULL, run, (void*)this); -#endif } thread::~thread() @@ -64,7 +60,6 @@ void *thread::run(void *arg) bool thread::join() { joined_ = true; -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) try { thread_.join(); return true; @@ -72,9 +67,6 @@ bool thread::join() catch (const std::system_error&) { return false; } -#else - return pthread_join(pthread_id_, NULL) == 0; -#endif } CCL_NAMESPACE_END diff --git a/intern/cycles/util/util_thread.h b/intern/cycles/util/util_thread.h index 77b51d37ea0..f39fcfb4279 100644 --- a/intern/cycles/util/util_thread.h +++ b/intern/cycles/util/util_thread.h @@ -17,15 +17,10 @@ #ifndef __UTIL_THREAD_H__ #define __UTIL_THREAD_H__ -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) -# include <thread> -# include <mutex> -# include <condition_variable> -# include <functional> -#else -# include <boost/thread.hpp> -# include <pthread.h> -#endif +#include <thread> +#include <mutex> +#include <condition_variable> +#include <functional> #include <queue> #ifdef _WIN32 @@ -42,16 +37,9 @@ CCL_NAMESPACE_BEGIN -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) typedef std::mutex thread_mutex; typedef std::unique_lock<std::mutex> thread_scoped_lock; typedef std::condition_variable thread_condition_variable; -#else -/* use boost for mutexes */ -typedef boost::mutex thread_mutex; -typedef boost::mutex::scoped_lock thread_scoped_lock; -typedef boost::condition_variable thread_condition_variable; -#endif /* own pthread based implementation, to avoid boost version conflicts with * dynamically loaded blender plugins */ @@ -66,11 +54,7 @@ public: protected: function<void(void)> run_cb_; -#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) std::thread thread_; -#else - pthread_t pthread_id_; -#endif bool joined_; int group_; }; diff --git a/intern/cycles/util/util_vector.h b/intern/cycles/util/util_vector.h index 569f503b66e..0b33221ad4d 100644 --- a/intern/cycles/util/util_vector.h +++ b/intern/cycles/util/util_vector.h @@ -59,11 +59,7 @@ public: void shrink_to_fit(void) { -#if __cplusplus < 201103L - vector<value_type>().swap(*this); -#else std::vector<value_type, allocator_type>::shrink_to_fit(); -#endif } void free_memory(void) |