diff options
author | YimingWu <xp8110@outlook.com> | 2019-09-05 06:36:05 +0300 |
---|---|---|
committer | YimingWu <xp8110@outlook.com> | 2019-09-05 06:36:05 +0300 |
commit | 7fb8ff3b2723a07ee1be79f27362548f8cf371ac (patch) | |
tree | 47e230f46da8df0aeea7c2b4188d0b9ce263728e /intern | |
parent | e80480ad415fe43e08a82d6e1e91a2dc0bc432d7 (diff) | |
parent | 6fc6f2504dfdae50c8184185222350052be0775c (diff) |
Merge remote-tracking branch 'origin/master' into temp-lanpr-staging
Diffstat (limited to 'intern')
46 files changed, 2394 insertions, 594 deletions
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index 9658c7b4a62..66d955768a3 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -29,6 +29,7 @@ set(SRC blender_shader.cpp blender_sync.cpp blender_texture.cpp + blender_viewport.cpp CCL_api.h blender_object_cull.h @@ -36,6 +37,7 @@ set(SRC blender_session.h blender_texture.h blender_util.h + blender_viewport.h ) set(LIB diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index b072d9e583e..6f2794531fd 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -2050,6 +2050,45 @@ class CYCLES_RENDER_PT_simplify_culling(CyclesButtonsPanel, Panel): sub.prop(cscene, "distance_cull_margin", text="Distance") +class CYCLES_VIEW3D_PT_shading_lighting(Panel): + bl_space_type = 'VIEW_3D' + bl_region_type = 'HEADER' + bl_label = "Lighting" + bl_parent_id = 'VIEW3D_PT_shading' + COMPAT_ENGINES = {'CYCLES'} + + @classmethod + def poll(cls, context): + return (context.engine in cls.COMPAT_ENGINES + and context.space_data.shading.type == 'RENDERED') + + def draw(self, context): + layout = self.layout + col = layout.column() + split = col.split(factor=0.9) + + shading = context.space_data.shading + col.prop(shading, "use_scene_lights_render") + col.prop(shading, "use_scene_world_render") + + if not shading.use_scene_world_render: + col = layout.column() + split = col.split(factor=0.9) + + col = split.column() + sub = col.row() + sub.scale_y = 0.6 + sub.template_icon_view(shading, "studio_light", scale_popup=3) + + col = split.column() + col.operator("preferences.studiolight_show", emboss=False, text="", icon='PREFERENCES') + + split = layout.split(factor=0.9) + col = split.column() + col.prop(shading, "studiolight_rotate_z", text="Rotation") + col.prop(shading, "studiolight_background_alpha") + + def draw_device(self, context): scene = context.scene layout = self.layout @@ -2131,6 +2170,7 @@ classes = ( CYCLES_RENDER_PT_simplify_viewport, CYCLES_RENDER_PT_simplify_render, CYCLES_RENDER_PT_simplify_culling, + CYCLES_VIEW3D_PT_shading_lighting, CYCLES_RENDER_PT_motion_blur, CYCLES_RENDER_PT_motion_blur_curve, CYCLES_RENDER_PT_film, diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index b670922ac88..b0599546244 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -239,7 +239,7 @@ void BlenderSync::sync_light(BL::Object &b_parent, light->tag_update(scene); } -void BlenderSync::sync_background_light(bool use_portal) +void BlenderSync::sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal) { BL::World b_world = b_scene.world(); @@ -283,6 +283,7 @@ void BlenderSync::sync_background_light(bool use_portal) world_map = b_world.ptr.data; world_recalc = false; + viewport_parameters = BlenderViewportParameters(b_v3d); } /* Object */ @@ -293,6 +294,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, float motion_time, bool show_self, bool show_particles, + bool show_lights, BlenderObjectCulling &culling, bool *use_portal) { @@ -311,6 +313,10 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, /* light is handled separately */ if (!motion && object_is_light(b_ob)) { + if (!show_lights) { + return NULL; + } + /* TODO: don't use lights for excluded layers used as mask layer, * when dynamic overrides are back. */ #if 0 @@ -507,7 +513,9 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph, /* Object Loop */ -void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, float motion_time) +void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, + BL::SpaceView3D &b_v3d, + float motion_time) { /* layer data */ bool motion = motion_time != 0.0f; @@ -530,6 +538,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, float motion_time) /* object loop */ bool cancel = false; bool use_portal = false; + const bool show_lights = BlenderViewportParameters(b_v3d).use_scene_lights; BL::ViewLayer b_view_layer = b_depsgraph.view_layer_eval(); @@ -555,6 +564,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, float motion_time) motion_time, show_self, show_particles, + show_lights, culling, &use_portal); } @@ -565,7 +575,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, float motion_time) progress.set_sync_status(""); if (!cancel && !motion) { - sync_background_light(use_portal); + sync_background_light(b_v3d, use_portal); /* handle removed data and modified pointers */ if (light_map.post_sync()) @@ -584,6 +594,7 @@ void BlenderSync::sync_objects(BL::Depsgraph &b_depsgraph, float motion_time) void BlenderSync::sync_motion(BL::RenderSettings &b_render, BL::Depsgraph &b_depsgraph, + BL::SpaceView3D &b_v3d, BL::Object &b_override, int width, int height, @@ -621,7 +632,7 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render, b_engine.frame_set(frame, subframe); python_thread_state_save(python_thread_state); sync_camera_motion(b_render, b_cam, width, height, 0.0f); - sync_objects(b_depsgraph, 0.0f); + sync_objects(b_depsgraph, b_v3d, 0.0f); } /* always sample these times for camera motion */ @@ -657,7 +668,7 @@ void BlenderSync::sync_motion(BL::RenderSettings &b_render, } /* sync object */ - sync_objects(b_depsgraph, relative_time); + sync_objects(b_depsgraph, b_v3d, relative_time); } /* we need to set the python thread state again because this diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 8923450c469..1f0816a6edb 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -861,7 +861,7 @@ void BlenderSession::synchronize(BL::Depsgraph &b_depsgraph_) /* copy recalc flags, outside of mutex so we can decide to do the real * synchronization at a later time to not block on running updates */ - sync->sync_recalc(b_depsgraph_); + sync->sync_recalc(b_depsgraph_, b_v3d); /* don't do synchronization if on pause */ if (session_pause) { diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 720f521c589..f5a76002eb6 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -208,24 +208,6 @@ static void get_tex_mapping(TextureMapping *mapping, BL::TexMapping &b_mapping) mapping->z_mapping = (TextureMapping::Mapping)b_mapping.mapping_z(); } -static void get_tex_mapping(TextureMapping *mapping, BL::ShaderNodeMapping &b_mapping) -{ - if (!b_mapping) - return; - - mapping->translation = get_float3(b_mapping.translation()); - mapping->rotation = get_float3(b_mapping.rotation()); - mapping->scale = get_float3(b_mapping.scale()); - mapping->type = (TextureMapping::Type)b_mapping.vector_type(); - - mapping->use_minmax = b_mapping.use_min() || b_mapping.use_max(); - - if (b_mapping.use_min()) - mapping->min = get_float3(b_mapping.min()); - if (b_mapping.use_max()) - mapping->max = get_float3(b_mapping.max()); -} - static ShaderNode *add_node(Scene *scene, BL::RenderEngine &b_engine, BL::BlendData &b_data, @@ -357,9 +339,7 @@ static ShaderNode *add_node(Scene *scene, else if (b_node.is_a(&RNA_ShaderNodeMapping)) { BL::ShaderNodeMapping b_mapping_node(b_node); MappingNode *mapping = new MappingNode(); - - get_tex_mapping(&mapping->tex_mapping, b_mapping_node); - + mapping->type = (NodeMappingType)b_mapping_node.vector_type(); node = mapping; } else if (b_node.is_a(&RNA_ShaderNodeFresnel)) { @@ -798,6 +778,7 @@ static ShaderNode *add_node(Scene *scene, else if (b_node.is_a(&RNA_ShaderNodeTexNoise)) { BL::ShaderNodeTexNoise b_noise_node(b_node); NoiseTextureNode *noise = new NoiseTextureNode(); + noise->dimensions = b_noise_node.dimensions(); BL::TexMapping b_texture_mapping(b_noise_node.texture_mapping()); get_tex_mapping(&noise->tex_mapping, b_texture_mapping); node = noise; @@ -1314,19 +1295,23 @@ void BlenderSync::sync_materials(BL::Depsgraph &b_depsgraph, bool update_all) /* Sync World */ -void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, bool update_all) +void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all) { Background *background = scene->background; Background prevbackground = *background; BL::World b_world = b_scene.world(); - if (world_recalc || update_all || b_world.ptr.data != world_map) { + BlenderViewportParameters new_viewport_parameters(b_v3d); + + if (world_recalc || update_all || b_world.ptr.data != world_map || + viewport_parameters.modified(new_viewport_parameters)) { Shader *shader = scene->default_background; ShaderGraph *graph = new ShaderGraph(); /* create nodes */ - if (b_world && b_world.use_nodes() && b_world.node_tree()) { + if (new_viewport_parameters.use_scene_world && b_world && b_world.use_nodes() && + b_world.node_tree()) { BL::ShaderNodeTree b_ntree(b_world.node_tree()); add_nodes(scene, b_engine, b_data, b_depsgraph, b_scene, graph, b_ntree); @@ -1337,7 +1322,7 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, bool update_all) shader->volume_sampling_method = get_volume_sampling(cworld); shader->volume_interpolation_method = get_volume_interpolation(cworld); } - else if (b_world) { + else if (new_viewport_parameters.use_scene_world && b_world) { BackgroundNode *background = new BackgroundNode(); background->color = get_float3(b_world.color()); graph->add(background); @@ -1345,6 +1330,45 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, bool update_all) ShaderNode *out = graph->output(); graph->connect(background->output("Background"), out->input("Surface")); } + else if (!new_viewport_parameters.use_scene_world) { + BackgroundNode *background = new BackgroundNode(); + graph->add(background); + + LightPathNode *light_path = new LightPathNode(); + graph->add(light_path); + + MixNode *mix_scene_with_background = new MixNode(); + mix_scene_with_background->color2 = get_float3(b_world.color()); + graph->add(mix_scene_with_background); + + EnvironmentTextureNode *texture_environment = new EnvironmentTextureNode(); + texture_environment->tex_mapping.type = TextureMapping::VECTOR; + texture_environment->tex_mapping.rotation[2] = new_viewport_parameters.studiolight_rotate_z; + texture_environment->filename = new_viewport_parameters.studiolight_path; + graph->add(texture_environment); + + TextureCoordinateNode *texture_coordinate = new TextureCoordinateNode(); + graph->add(texture_coordinate); + + MixNode *mix_background_with_environment = new MixNode(); + mix_background_with_environment->fac = new_viewport_parameters.studiolight_background_alpha; + mix_background_with_environment->color1 = get_float3(b_world.color()); + graph->add(mix_background_with_environment); + + ShaderNode *out = graph->output(); + + graph->connect(texture_coordinate->output("Generated"), + texture_environment->input("Vector")); + graph->connect(light_path->output("Is Camera Ray"), mix_scene_with_background->input("Fac")); + graph->connect(texture_environment->output("Color"), + mix_scene_with_background->input("Color1")); + graph->connect(texture_environment->output("Color"), + mix_background_with_environment->input("Color2")); + graph->connect(mix_background_with_environment->output("Color"), + mix_scene_with_background->input("Color2")); + graph->connect(mix_scene_with_background->output("Color"), background->input("Color")); + graph->connect(background->output("Background"), out->input("Surface")); + } if (b_world) { /* AO */ @@ -1389,7 +1413,8 @@ void BlenderSync::sync_world(BL::Depsgraph &b_depsgraph, bool update_all) background->transparent_roughness_threshold = 0.0f; } - background->use_shader = view_layer.use_background_shader; + background->use_shader = view_layer.use_background_shader | + viewport_parameters.custom_viewport_parameters(); background->use_ao = background->use_ao && view_layer.use_background_ao; if (background->modified(prevbackground)) @@ -1439,7 +1464,7 @@ void BlenderSync::sync_lights(BL::Depsgraph &b_depsgraph, bool update_all) } } -void BlenderSync::sync_shaders(BL::Depsgraph &b_depsgraph) +void BlenderSync::sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d) { /* for auto refresh images */ bool auto_refresh_update = false; @@ -1452,7 +1477,7 @@ void BlenderSync::sync_shaders(BL::Depsgraph &b_depsgraph) shader_map.pre_sync(); - sync_world(b_depsgraph, auto_refresh_update); + sync_world(b_depsgraph, b_v3d, auto_refresh_update); sync_lights(b_depsgraph, auto_refresh_update); sync_materials(b_depsgraph, auto_refresh_update); } diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index aec21887088..e50d96cf345 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -80,7 +80,7 @@ BlenderSync::~BlenderSync() /* Sync */ -void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph) +void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d) { /* Sync recalc flags from blender to cycles. Actual update is done separate, * so we can do it later on if doing it immediate is not suitable. */ @@ -175,6 +175,11 @@ void BlenderSync::sync_recalc(BL::Depsgraph &b_depsgraph) } } + BlenderViewportParameters new_viewport_parameters(b_v3d); + if (viewport_parameters.modified(new_viewport_parameters)) { + world_recalc = true; + } + /* Updates shader with object dependency if objects changed. */ if (has_updated_objects) { if (scene->default_background->has_object_dependency) { @@ -202,7 +207,7 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render, sync_view_layer(b_v3d, b_view_layer); sync_integrator(); sync_film(); - sync_shaders(b_depsgraph); + sync_shaders(b_depsgraph, b_v3d); sync_images(); sync_curve_settings(); @@ -210,9 +215,9 @@ void BlenderSync::sync_data(BL::RenderSettings &b_render, if (scene->need_motion() == Scene::MOTION_PASS || scene->need_motion() == Scene::MOTION_NONE || scene->camera->motion_position == Camera::MOTION_POSITION_CENTER) { - sync_objects(b_depsgraph); + sync_objects(b_depsgraph, b_v3d); } - sync_motion(b_render, b_depsgraph, b_override, width, height, python_thread_state); + sync_motion(b_render, b_depsgraph, b_v3d, b_override, width, height, python_thread_state); mesh_synced.clear(); diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 00afceebde3..c6c7b7549cf 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -23,6 +23,7 @@ #include "RNA_blender_cpp.h" #include "blender/blender_util.h" +#include "blender/blender_viewport.h" #include "render/scene.h" #include "render/session.h" @@ -36,6 +37,7 @@ CCL_NAMESPACE_BEGIN class Background; class BlenderObjectCulling; +class BlenderViewportParameters; class Camera; class Film; class Light; @@ -59,7 +61,7 @@ class BlenderSync { ~BlenderSync(); /* sync */ - void sync_recalc(BL::Depsgraph &b_depsgraph); + void sync_recalc(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d); void sync_data(BL::RenderSettings &b_render, BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, @@ -106,17 +108,18 @@ class BlenderSync { /* sync */ void sync_lights(BL::Depsgraph &b_depsgraph, bool update_all); void sync_materials(BL::Depsgraph &b_depsgraph, bool update_all); - void sync_objects(BL::Depsgraph &b_depsgraph, float motion_time = 0.0f); + void sync_objects(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, float motion_time = 0.0f); void sync_motion(BL::RenderSettings &b_render, BL::Depsgraph &b_depsgraph, + BL::SpaceView3D &b_v3d, BL::Object &b_override, int width, int height, void **python_thread_state); void sync_film(); void sync_view(); - void sync_world(BL::Depsgraph &b_depsgraph, bool update_all); - void sync_shaders(BL::Depsgraph &b_depsgraph); + void sync_world(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d, bool update_all); + void sync_shaders(BL::Depsgraph &b_depsgraph, BL::SpaceView3D &b_v3d); void sync_curve_settings(); void sync_nodes(Shader *shader, BL::ShaderNodeTree &b_ntree); @@ -134,6 +137,7 @@ class BlenderSync { float motion_time, bool show_self, bool show_particles, + bool show_lights, BlenderObjectCulling &culling, bool *use_portal); void sync_light(BL::Object &b_parent, @@ -143,7 +147,7 @@ class BlenderSync { int random_id, Transform &tfm, bool *use_portal); - void sync_background_light(bool use_portal); + void sync_background_light(BL::SpaceView3D &b_v3d, bool use_portal); void sync_mesh_motion(BL::Depsgraph &b_depsgraph, BL::Object &b_ob, Object *object, @@ -183,6 +187,7 @@ class BlenderSync { set<float> motion_times; void *world_map; bool world_recalc; + BlenderViewportParameters viewport_parameters; Scene *scene; bool preview; diff --git a/intern/cycles/blender/blender_viewport.cpp b/intern/cycles/blender/blender_viewport.cpp new file mode 100644 index 00000000000..7af509aab09 --- /dev/null +++ b/intern/cycles/blender/blender_viewport.cpp @@ -0,0 +1,59 @@ +/* + * Copyright 2019 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 "blender_viewport.h" + +CCL_NAMESPACE_BEGIN + +BlenderViewportParameters::BlenderViewportParameters() + : use_scene_world(true), + use_scene_lights(true), + studiolight_rotate_z(0.0f), + studiolight_background_alpha(1.0f), + studiolight_path(ustring()) +{ +} + +BlenderViewportParameters::BlenderViewportParameters(BL::SpaceView3D &b_v3d) + : BlenderViewportParameters() +{ + /* We only copy the parameters if we are in look dev mode. otherwise + * defaults are being used. These defaults mimic normal render settings */ + if (b_v3d && b_v3d.shading().type() == BL::View3DShading::type_RENDERED) { + use_scene_world = b_v3d.shading().use_scene_world_render(); + use_scene_lights = b_v3d.shading().use_scene_lights_render(); + if (!use_scene_world) { + studiolight_rotate_z = b_v3d.shading().studiolight_rotate_z(); + studiolight_background_alpha = b_v3d.shading().studiolight_background_alpha(); + studiolight_path = b_v3d.shading().selected_studio_light().path(); + } + } +} + +/* Check if two instances are different. */ +const bool BlenderViewportParameters::modified(const BlenderViewportParameters &other) const +{ + return use_scene_world != other.use_scene_world || use_scene_lights != other.use_scene_lights || + studiolight_rotate_z != other.studiolight_rotate_z || + studiolight_background_alpha != other.studiolight_background_alpha || + studiolight_path != other.studiolight_path; +} + +const bool BlenderViewportParameters::custom_viewport_parameters() const +{ + return !(use_scene_world && use_scene_lights); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_viewport.h b/intern/cycles/blender/blender_viewport.h new file mode 100644 index 00000000000..bb0d7d7f314 --- /dev/null +++ b/intern/cycles/blender/blender_viewport.h @@ -0,0 +1,47 @@ +/* + * Copyright 2019 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 __BLENDER_VIEWPORT_H__ +#define __BLENDER_VIEWPORT_H__ + +#include "MEM_guardedalloc.h" +#include "RNA_types.h" +#include "RNA_access.h" +#include "RNA_blender_cpp.h" + +#include "util/util_param.h" + +CCL_NAMESPACE_BEGIN + +class BlenderViewportParameters { + private: + bool use_scene_world; + bool use_scene_lights; + float studiolight_rotate_z; + float studiolight_background_alpha; + ustring studiolight_path; + + BlenderViewportParameters(); + BlenderViewportParameters(BL::SpaceView3D &b_v3d); + + const bool modified(const BlenderViewportParameters &other) const; + const bool custom_viewport_parameters() const; + friend class BlenderSync; +}; + +CCL_NAMESPACE_END + +#endif
\ No newline at end of file diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 48439a8b68f..04df49aa058 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -201,6 +201,7 @@ set(SRC_SVM_HEADERS svm/svm_magic.h svm/svm_map_range.h svm/svm_mapping.h + svm/svm_mapping_util.h svm/svm_math.h svm/svm_math_util.h svm/svm_mix.h @@ -214,7 +215,7 @@ set(SRC_SVM_HEADERS svm/svm_sepcomb_vector.h svm/svm_sky.h svm/svm_tex_coord.h - svm/svm_texture.h + svm/svm_fractal_noise.h svm/svm_types.h svm/svm_value.h svm/svm_vector_transform.h diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index c50bffe27b2..a45c43e01ed 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -97,10 +97,12 @@ set(SRC_OSL set(SRC_OSL_HEADERS node_color.h node_fresnel.h + node_noise.h node_ramp_util.h - node_texture.h stdosl.h oslutil.h + vector2.h + vector4.h ) set(SRC_OSO diff --git a/intern/cycles/kernel/shaders/node_brick_texture.osl b/intern/cycles/kernel/shaders/node_brick_texture.osl index 0abc3574c48..30644ef2ff3 100644 --- a/intern/cycles/kernel/shaders/node_brick_texture.osl +++ b/intern/cycles/kernel/shaders/node_brick_texture.osl @@ -15,7 +15,6 @@ */ #include "stdosl.h" -#include "node_texture.h" /* Brick */ diff --git a/intern/cycles/kernel/shaders/node_checker_texture.osl b/intern/cycles/kernel/shaders/node_checker_texture.osl index e068f7952ed..e05cf20099f 100644 --- a/intern/cycles/kernel/shaders/node_checker_texture.osl +++ b/intern/cycles/kernel/shaders/node_checker_texture.osl @@ -15,7 +15,6 @@ */ #include "stdosl.h" -#include "node_texture.h" /* Checker */ diff --git a/intern/cycles/kernel/shaders/node_gradient_texture.osl b/intern/cycles/kernel/shaders/node_gradient_texture.osl index 52bf466673d..5cc81d367f2 100644 --- a/intern/cycles/kernel/shaders/node_gradient_texture.osl +++ b/intern/cycles/kernel/shaders/node_gradient_texture.osl @@ -15,7 +15,6 @@ */ #include "stdosl.h" -#include "node_texture.h" /* Gradient */ diff --git a/intern/cycles/kernel/shaders/node_ies_light.osl b/intern/cycles/kernel/shaders/node_ies_light.osl index ce0173451da..6e9181cde40 100644 --- a/intern/cycles/kernel/shaders/node_ies_light.osl +++ b/intern/cycles/kernel/shaders/node_ies_light.osl @@ -15,7 +15,6 @@ */ #include "stdosl.h" -#include "node_texture.h" /* IES Light */ diff --git a/intern/cycles/kernel/shaders/node_magic_texture.osl b/intern/cycles/kernel/shaders/node_magic_texture.osl index aa700e575ef..26e7d57278b 100644 --- a/intern/cycles/kernel/shaders/node_magic_texture.osl +++ b/intern/cycles/kernel/shaders/node_magic_texture.osl @@ -15,7 +15,6 @@ */ #include "stdosl.h" -#include "node_texture.h" /* Magic */ diff --git a/intern/cycles/kernel/shaders/node_mapping.osl b/intern/cycles/kernel/shaders/node_mapping.osl index f5cc2d1c5dd..8eed0ae9c48 100644 --- a/intern/cycles/kernel/shaders/node_mapping.osl +++ b/intern/cycles/kernel/shaders/node_mapping.osl @@ -16,17 +16,58 @@ #include "stdosl.h" -shader node_mapping(matrix Matrix = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - point mapping_min = point(0.0, 0.0, 0.0), - point mapping_max = point(0.0, 0.0, 0.0), - int use_minmax = 0, - point VectorIn = point(0.0, 0.0, 0.0), - output point VectorOut = point(0.0, 0.0, 0.0)) +point safe_divide(point a, point b) +{ + return point((b[0] != 0.0) ? a[0] / b[0] : 0.0, + (b[1] != 0.0) ? a[1] / b[1] : 0.0, + (b[2] != 0.0) ? a[2] / b[2] : 0.0); +} + +matrix euler_to_mat(point euler) { - point p = transform(Matrix, VectorIn); + float cx = cos(euler[0]); + float cy = cos(euler[1]); + float cz = cos(euler[2]); + float sx = sin(euler[0]); + float sy = sin(euler[1]); + float sz = sin(euler[2]); + + matrix mat = matrix(1.0); + mat[0][0] = cy * cz; + mat[0][1] = cy * sz; + mat[0][2] = -sy; - if (use_minmax) - p = min(max(mapping_min, p), mapping_max); + mat[1][0] = sy * sx * cz - cx * sz; + mat[1][1] = sy * sx * sz + cx * cz; + mat[1][2] = cy * sx; - VectorOut = p; + mat[2][0] = sy * cx * cz + sx * sz; + mat[2][1] = sy * cx * sz - sx * cz; + mat[2][2] = cy * cx; + return mat; +} + +shader node_mapping(string type = "point", + point VectorIn = point(0.0, 0.0, 0.0), + point Location = point(0.0, 0.0, 0.0), + point Rotation = point(0.0, 0.0, 0.0), + point Scale = point(1.0, 1.0, 1.0), + output point VectorOut = point(0.0, 0.0, 0.0)) +{ + if (type == "point") { + VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale)) + Location; + } + else if (type == "texture") { + VectorOut = safe_divide(transform(transpose(euler_to_mat(Rotation)), (VectorIn - Location)), + Scale); + } + else if (type == "vector") { + VectorOut = transform(euler_to_mat(Rotation), (VectorIn * Scale)); + } + else if (type == "normal") { + VectorOut = normalize(transform(euler_to_mat(Rotation), safe_divide(VectorIn, Scale))); + } + else { + warning("%s", "Unknown Mapping vector type!"); + } } diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/shaders/node_musgrave_texture.osl index a7877c43d46..0bf462e2103 100644 --- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl +++ b/intern/cycles/kernel/shaders/node_musgrave_texture.osl @@ -15,7 +15,7 @@ */ #include "stdosl.h" -#include "node_texture.h" +#include "node_noise.h" /* Musgrave fBm * @@ -36,14 +36,14 @@ float noise_musgrave_fBm(point ip, float H, float lacunarity, float octaves) point p = ip; for (i = 0; i < (int)octaves; i++) { - value += safe_noise(p, "signed") * pwr; + value += safe_noise(p) * pwr; pwr *= pwHL; p *= lacunarity; } rmd = octaves - floor(octaves); if (rmd != 0.0) - value += rmd * safe_noise(p, "signed") * pwr; + value += rmd * safe_noise(p) * pwr; return value; } @@ -65,14 +65,14 @@ float noise_musgrave_multi_fractal(point ip, float H, float lacunarity, float oc point p = ip; for (i = 0; i < (int)octaves; i++) { - value *= (pwr * safe_noise(p, "signed") + 1.0); + value *= (pwr * safe_noise(p) + 1.0); pwr *= pwHL; p *= lacunarity; } rmd = octaves - floor(octaves); if (rmd != 0.0) - value *= (rmd * pwr * safe_noise(p, "signed") + 1.0); /* correct? */ + value *= (rmd * pwr * safe_noise(p) + 1.0); /* correct? */ return value; } @@ -95,11 +95,11 @@ float noise_musgrave_hetero_terrain( point p = ip; /* first unscaled octave of function; later octaves are scaled */ - value = offset + safe_noise(p, "signed"); + value = offset + safe_noise(p); p *= lacunarity; for (i = 1; i < (int)octaves; i++) { - increment = (safe_noise(p, "signed") + offset) * pwr * value; + increment = (safe_noise(p) + offset) * pwr * value; value += increment; pwr *= pwHL; p *= lacunarity; @@ -107,7 +107,7 @@ float noise_musgrave_hetero_terrain( rmd = octaves - floor(octaves); if (rmd != 0.0) { - increment = (safe_noise(p, "signed") + offset) * pwr * value; + increment = (safe_noise(p) + offset) * pwr * value; value += rmd * increment; } @@ -131,7 +131,7 @@ float noise_musgrave_hybrid_multi_fractal( int i; point p = ip; - result = safe_noise(p, "signed") + offset; + result = safe_noise(p) + offset; weight = gain * result; p *= lacunarity; @@ -139,7 +139,7 @@ float noise_musgrave_hybrid_multi_fractal( if (weight > 1.0) weight = 1.0; - signal = (safe_noise(p, "signed") + offset) * pwr; + signal = (safe_noise(p) + offset) * pwr; pwr *= pwHL; result += weight * signal; weight *= gain * signal; @@ -148,7 +148,7 @@ float noise_musgrave_hybrid_multi_fractal( rmd = octaves - floor(octaves); if (rmd != 0.0) - result += rmd * ((safe_noise(p, "signed") + offset) * pwr); + result += rmd * ((safe_noise(p) + offset) * pwr); return result; } @@ -170,7 +170,7 @@ float noise_musgrave_ridged_multi_fractal( int i; point p = ip; - signal = offset - fabs(safe_noise(p, "signed")); + signal = offset - fabs(safe_noise(p)); signal *= signal; result = signal; weight = 1.0; @@ -178,7 +178,7 @@ float noise_musgrave_ridged_multi_fractal( for (i = 1; i < (int)octaves; i++) { p *= lacunarity; weight = clamp(signal * gain, 0.0, 1.0); - signal = offset - fabs(safe_noise(p, "signed")); + signal = offset - fabs(safe_noise(p)); signal *= signal; signal *= weight; result += signal * pwr; diff --git a/intern/cycles/kernel/shaders/node_noise.h b/intern/cycles/kernel/shaders/node_noise.h new file mode 100644 index 00000000000..23d1987a00e --- /dev/null +++ b/intern/cycles/kernel/shaders/node_noise.h @@ -0,0 +1,198 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "vector2.h" +#include "vector4.h" + +#define vector3 point + +float safe_noise(float p) +{ + float f = noise("noise", p); + if (isinf(f)) + return 0.5; + return f; +} + +float safe_noise(vector2 p) +{ + float f = noise("noise", p.x, p.y); + if (isinf(f)) + return 0.5; + return f; +} + +float safe_noise(vector3 p) +{ + float f = noise("noise", p); + if (isinf(f)) + return 0.5; + return f; +} + +float safe_noise(vector4 p) +{ + float f = noise("noise", vector3(p.x, p.y, p.z), p.w); + if (isinf(f)) + return 0.5; + return f; +} + +float safe_snoise(float p) +{ + float f = noise("snoise", p); + if (isinf(f)) + return 0.0; + return f; +} + +float safe_snoise(vector2 p) +{ + float f = noise("snoise", p.x, p.y); + if (isinf(f)) + return 0.0; + return f; +} + +float safe_snoise(vector3 p) +{ + float f = noise("snoise", p); + if (isinf(f)) + return 0.0; + return f; +} + +float safe_snoise(vector4 p) +{ + float f = noise("snoise", vector3(p.x, p.y, p.z), p.w); + if (isinf(f)) + return 0.0; + return f; +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(float p, float details) +{ + float fscale = 1.0; + float amp = 1.0; + float sum = 0.0; + float octaves = clamp(details, 0.0, 16.0); + int n = (int)octaves; + for (int i = 0; i <= n; i++) { + float t = safe_noise(fscale * p); + sum += t * amp; + amp *= 0.5; + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = safe_noise(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(vector2 p, float details) +{ + float fscale = 1.0; + float amp = 1.0; + float sum = 0.0; + float octaves = clamp(details, 0.0, 16.0); + int n = (int)octaves; + for (int i = 0; i <= n; i++) { + float t = safe_noise(fscale * p); + sum += t * amp; + amp *= 0.5; + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = safe_noise(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(vector3 p, float details) +{ + float fscale = 1.0; + float amp = 1.0; + float sum = 0.0; + float octaves = clamp(details, 0.0, 16.0); + int n = (int)octaves; + for (int i = 0; i <= n; i++) { + float t = safe_noise(fscale * p); + sum += t * amp; + amp *= 0.5; + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = safe_noise(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise functions are all exactly the same except for the input type. */ +float fractal_noise(vector4 p, float details) +{ + float fscale = 1.0; + float amp = 1.0; + float sum = 0.0; + float octaves = clamp(details, 0.0, 16.0); + int n = (int)octaves; + for (int i = 0; i <= n; i++) { + float t = safe_noise(fscale * p); + sum += t * amp; + amp *= 0.5; + fscale *= 2.0; + } + float rmd = octaves - floor(octaves); + if (rmd != 0.0) { + float t = safe_noise(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0 - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +#undef vector3 diff --git a/intern/cycles/kernel/shaders/node_noise_texture.osl b/intern/cycles/kernel/shaders/node_noise_texture.osl index 2cbd571e206..242a7e33f60 100644 --- a/intern/cycles/kernel/shaders/node_noise_texture.osl +++ b/intern/cycles/kernel/shaders/node_noise_texture.osl @@ -15,46 +15,134 @@ */ #include "stdosl.h" -#include "node_texture.h" +#include "vector2.h" +#include "vector4.h" +#include "node_noise.h" -/* Noise */ +#define vector3 point -float noise(point ip, float distortion, float detail, output color Color) +/* The following offset functions generate random offsets to be added to texture + * coordinates to act as a seed since the noise functions don't have seed values. + * A seed value is needed for generating distortion textures and color outputs. + * The offset's components are in the range [100, 200], not too high to cause + * bad precision and not to small to be noticeable. We use float seed because + * OSL only support float hashes. + */ + +float random_float_offset(float seed) +{ + return 100.0 + noise("hash", seed) * 100.0; +} + +vector2 random_vector2_offset(float seed) +{ + return vector2(100.0 + noise("hash", seed, 0.0) * 100.0, + 100.0 + noise("hash", seed, 1.0) * 100.0); +} + +vector3 random_vector3_offset(float seed) { - point r; - point p = ip; - int hard = 0; + return vector3(100.0 + noise("hash", seed, 0.0) * 100.0, + 100.0 + noise("hash", seed, 1.0) * 100.0, + 100.0 + noise("hash", seed, 2.0) * 100.0); +} + +vector4 random_vector4_offset(float seed) +{ + return vector4(100.0 + noise("hash", seed, 0.0) * 100.0, + 100.0 + noise("hash", seed, 1.0) * 100.0, + 100.0 + noise("hash", seed, 2.0) * 100.0, + 100.0 + noise("hash", seed, 3.0) * 100.0); +} +float noise_texture(float co, float detail, float distortion, output color Color) +{ + float p = co; if (distortion != 0.0) { - r[0] = safe_noise(p + point(13.5), "unsigned") * distortion; - r[1] = safe_noise(p, "unsigned") * distortion; - r[2] = safe_noise(p - point(13.5), "unsigned") * distortion; + p += safe_noise(p + random_float_offset(0.0)) * distortion; + } + + float value = fractal_noise(p, detail); + Color = color(value, + fractal_noise(p + random_float_offset(1.0), detail), + fractal_noise(p + random_float_offset(2.0), detail)); + return value; +} - p += r; +float noise_texture(vector2 co, float detail, float distortion, output color Color) +{ + vector2 p = co; + if (distortion != 0.0) { + p += vector2(safe_noise(p + random_vector2_offset(0.0)) * distortion, + safe_noise(p + random_vector2_offset(1.0)) * distortion); } - float fac = noise_turbulence(p, detail, hard); + float value = fractal_noise(p, detail); + Color = color(value, + fractal_noise(p + random_vector2_offset(2.0), detail), + fractal_noise(p + random_vector2_offset(3.0), detail)); + return value; +} - Color = color(fac, - noise_turbulence(point(p[1], p[0], p[2]), detail, hard), - noise_turbulence(point(p[1], p[2], p[0]), detail, hard)); +float noise_texture(vector3 co, float detail, float distortion, output color Color) +{ + vector3 p = co; + if (distortion != 0.0) { + p += vector3(safe_noise(p + random_vector3_offset(0.0)) * distortion, + safe_noise(p + random_vector3_offset(1.0)) * distortion, + safe_noise(p + random_vector3_offset(2.0)) * distortion); + } - return fac; + float value = fractal_noise(p, detail); + Color = color(value, + fractal_noise(p + random_vector3_offset(3.0), detail), + fractal_noise(p + random_vector3_offset(4.0), detail)); + return value; +} + +float noise_texture(vector4 co, float detail, float distortion, output color Color) +{ + vector4 p = co; + if (distortion != 0.0) { + p += vector4(safe_noise(p + random_vector4_offset(0.0)) * distortion, + safe_noise(p + random_vector4_offset(1.0)) * distortion, + safe_noise(p + random_vector4_offset(2.0)) * distortion, + safe_noise(p + random_vector4_offset(3.0)) * distortion); + } + + float value = fractal_noise(p, detail); + Color = color(value, + fractal_noise(p + random_vector4_offset(4.0), detail), + fractal_noise(p + random_vector4_offset(5.0), detail)); + return value; } shader node_noise_texture(int use_mapping = 0, matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), - float Distortion = 0.0, + string dimensions = "3D", + vector3 Vector = vector3(0, 0, 0), + float W = 0.0, float Scale = 5.0, float Detail = 2.0, - point Vector = P, + float Distortion = 0.0, output float Fac = 0.0, output color Color = 0.0) { - point p = Vector; - + vector3 p = Vector; if (use_mapping) p = transform(mapping, p); + + p *= Scale; + float w = W * Scale; - Fac = noise(p * Scale, Distortion, Detail, Color); + if (dimensions == "1D") + Fac = noise_texture(w, Detail, Distortion, Color); + else if (dimensions == "2D") + Fac = noise_texture(vector2(p[0], p[1]), Detail, Distortion, Color); + else if (dimensions == "3D") + Fac = noise_texture(p, Detail, Distortion, Color); + else if (dimensions == "4D") + Fac = noise_texture(vector4(p[0], p[1], p[2], w), Detail, Distortion, Color); + else + error("Unknown dimension!"); } diff --git a/intern/cycles/kernel/shaders/node_texture.h b/intern/cycles/kernel/shaders/node_texture.h deleted file mode 100644 index e1f3b900ee5..00000000000 --- a/intern/cycles/kernel/shaders/node_texture.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2011-2013 Blender Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* Voronoi / Worley like */ - -color cellnoise_color(point p) -{ - float r = cellnoise(p); - float g = cellnoise(point(p[1], p[0], p[2])); - float b = cellnoise(point(p[1], p[2], p[0])); - - return color(r, g, b); -} - -void voronoi(point p, float e, float da[4], point pa[4]) -{ - /* returns distances in da and point coords in pa */ - int xx, yy, zz, xi, yi, zi; - - xi = (int)floor(p[0]); - yi = (int)floor(p[1]); - zi = (int)floor(p[2]); - - da[0] = 1e10; - da[1] = 1e10; - da[2] = 1e10; - da[3] = 1e10; - - for (xx = xi - 1; xx <= xi + 1; xx++) { - for (yy = yi - 1; yy <= yi + 1; yy++) { - for (zz = zi - 1; zz <= zi + 1; zz++) { - point ip = point(xx, yy, zz); - point vp = (point)cellnoise_color(ip); - point pd = p - (vp + ip); - float d = dot(pd, pd); - - vp += point(xx, yy, zz); - - if (d < da[0]) { - da[3] = da[2]; - da[2] = da[1]; - da[1] = da[0]; - da[0] = d; - - pa[3] = pa[2]; - pa[2] = pa[1]; - pa[1] = pa[0]; - pa[0] = vp; - } - else if (d < da[1]) { - da[3] = da[2]; - da[2] = da[1]; - da[1] = d; - - pa[3] = pa[2]; - pa[2] = pa[1]; - pa[1] = vp; - } - else if (d < da[2]) { - da[3] = da[2]; - da[2] = d; - - pa[3] = pa[2]; - pa[2] = vp; - } - else if (d < da[3]) { - da[3] = d; - pa[3] = vp; - } - } - } - } -} - -/* Noise Bases */ - -float safe_noise(point p, string type) -{ - float f = 0.0; - - /* Perlin noise in range -1..1 */ - if (type == "signed") - f = noise("perlin", p); - - /* Perlin noise in range 0..1 */ - else - f = noise(p); - - /* can happen for big coordinates, things even out to 0.5 then anyway */ - if (!isfinite(f)) - return 0.5; - - return f; -} - -/* Turbulence */ - -float noise_turbulence(point p, float details, int hard) -{ - float fscale = 1.0; - float amp = 1.0; - float sum = 0.0; - int i, n; - - float octaves = clamp(details, 0.0, 16.0); - n = (int)octaves; - - for (i = 0; i <= n; i++) { - float t = safe_noise(fscale * p, "unsigned"); - - if (hard) - t = fabs(2.0 * t - 1.0); - - sum += t * amp; - amp *= 0.5; - fscale *= 2.0; - } - - float rmd = octaves - floor(octaves); - - if (rmd != 0.0) { - float t = safe_noise(fscale * p, "unsigned"); - - if (hard) - t = fabs(2.0 * t - 1.0); - - float sum2 = sum + t * amp; - - sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); - sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); - - return (1.0 - rmd) * sum + rmd * sum2; - } - else { - sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); - return sum; - } -} - -/* Utility */ - -float nonzero(float f, float eps) -{ - float r; - - if (abs(f) < eps) - r = sign(f) * eps; - else - r = f; - - return r; -} diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl index 34c86d5b98d..0d547b4b615 100644 --- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl +++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl @@ -15,7 +15,15 @@ */ #include "stdosl.h" -#include "node_texture.h" + +color cellnoise_color(point p) +{ + float r = cellnoise(p); + float g = cellnoise(point(p[1], p[0], p[2])); + float b = cellnoise(point(p[1], p[2], p[0])); + + return color(r, g, b); +} void voronoi_m(point p, string metric, float e, float da[4], point pa[4]) { diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl index dfc2dbfb800..60591b79b33 100644 --- a/intern/cycles/kernel/shaders/node_wave_texture.osl +++ b/intern/cycles/kernel/shaders/node_wave_texture.osl @@ -15,7 +15,7 @@ */ #include "stdosl.h" -#include "node_texture.h" +#include "node_noise.h" /* Wave */ @@ -31,7 +31,7 @@ float wave(point p, string type, string profile, float detail, float distortion, } if (distortion != 0.0) { - n = n + (distortion * noise_turbulence(p * dscale, detail, 0)); + n = n + (distortion * fractal_noise(p * dscale, detail)); } if (profile == "sine") { diff --git a/intern/cycles/kernel/shaders/vector2.h b/intern/cycles/kernel/shaders/vector2.h new file mode 100644 index 00000000000..c524735d892 --- /dev/null +++ b/intern/cycles/kernel/shaders/vector2.h @@ -0,0 +1,291 @@ +// Open Shading Language : Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al. +// https://github.com/imageworks/OpenShadingLanguage/blob/master/LICENSE + +#pragma once +#define VECTOR2_H + +// vector2 is a 2D vector +struct vector2 { + float x; + float y; +}; + +// +// For vector2, define math operators to match vector +// + +vector2 __operator__neg__(vector2 a) +{ + return vector2(-a.x, -a.y); +} + +vector2 __operator__add__(vector2 a, vector2 b) +{ + return vector2(a.x + b.x, a.y + b.y); +} + +vector2 __operator__add__(vector2 a, int b) +{ + return a + vector2(b, b); +} + +vector2 __operator__add__(vector2 a, float b) +{ + return a + vector2(b, b); +} + +vector2 __operator__add__(int a, vector2 b) +{ + return vector2(a, a) + b; +} + +vector2 __operator__add__(float a, vector2 b) +{ + return vector2(a, a) + b; +} + +vector2 __operator__sub__(vector2 a, vector2 b) +{ + return vector2(a.x - b.x, a.y - b.y); +} + +vector2 __operator__sub__(vector2 a, int b) +{ + return a - vector2(b, b); +} + +vector2 __operator__sub__(vector2 a, float b) +{ + return a - vector2(b, b); +} + +vector2 __operator__sub__(int a, vector2 b) +{ + return vector2(a, a) - b; +} + +vector2 __operator__sub__(float a, vector2 b) +{ + return vector2(a, a) - b; +} + +vector2 __operator__mul__(vector2 a, vector2 b) +{ + return vector2(a.x * b.x, a.y * b.y); +} + +vector2 __operator__mul__(vector2 a, int b) +{ + return a * vector2(b, b); +} + +vector2 __operator__mul__(vector2 a, float b) +{ + return a * vector2(b, b); +} + +vector2 __operator__mul__(int a, vector2 b) +{ + return b * vector2(a, a); +} + +vector2 __operator__mul__(float a, vector2 b) +{ + return b * vector2(a, a); +} + +vector2 __operator__div__(vector2 a, vector2 b) +{ + return vector2(a.x / b.x, a.y / b.y); +} + +vector2 __operator__div__(vector2 a, int b) +{ + float b_inv = 1 / b; + return a * vector2(b_inv, b_inv); +} + +vector2 __operator__div__(vector2 a, float b) +{ + float b_inv = 1 / b; + return a * vector2(b_inv, b_inv); +} + +vector2 __operator__div__(int a, vector2 b) +{ + return vector2(a, a) / b; +} + +vector2 __operator__div__(float a, vector2 b) +{ + return vector2(a, a) / b; +} + +int __operator__eq__(vector2 a, vector2 b) +{ + return (a.x == b.x) && (a.y == b.y); +} + +int __operator__ne__(vector2 a, vector2 b) +{ + return (a.x != b.x) || (a.y != b.y); +} + +// +// For vector2, define most of the stdosl functions to match vector +// + +vector2 abs(vector2 a) +{ + return vector2(abs(a.x), abs(a.y)); +} + +vector2 ceil(vector2 a) +{ + return vector2(ceil(a.x), ceil(a.y)); +} + +vector2 floor(vector2 a) +{ + return vector2(floor(a.x), floor(a.y)); +} + +vector2 sqrt(vector2 a) +{ + return vector2(sqrt(a.x), sqrt(a.y)); +} + +vector2 exp(vector2 a) +{ + return vector2(exp(a.x), exp(a.y)); +} + +vector2 log(vector2 a) +{ + return vector2(log(a.x), log(a.y)); +} + +vector2 log2(vector2 a) +{ + return vector2(log2(a.x), log2(a.y)); +} + +vector2 mix(vector2 a, vector2 b, float x) +{ + return vector2(mix(a.x, b.x, x), mix(a.y, b.y, x)); +} + +float dot(vector2 a, vector2 b) +{ + return (a.x * b.x + a.y * b.y); +} + +float length(vector2 a) +{ + return hypot(a.x, a.y); +} + +vector2 smoothstep(vector2 low, vector2 high, vector2 in) +{ + return vector2(smoothstep(low.x, high.x, in.x), smoothstep(low.y, high.y, in.y)); +} + +vector2 smoothstep(float low, float high, vector2 in) +{ + return vector2(smoothstep(low, high, in.x), smoothstep(low, high, in.y)); +} + +vector2 clamp(vector2 in, vector2 low, vector2 high) +{ + return vector2(clamp(in.x, low.x, high.x), clamp(in.y, low.y, high.y)); +} + +vector2 clamp(vector2 in, float low, float high) +{ + return clamp(in, vector2(low, low), vector2(high, high)); +} + +vector2 max(vector2 a, vector2 b) +{ + return vector2(max(a.x, b.x), max(a.y, b.y)); +} + +vector2 max(vector2 a, float b) +{ + return max(a, vector2(b, b)); +} + +vector2 normalize(vector2 a) +{ + return a / length(a); +} + +vector2 min(vector2 a, vector2 b) +{ + return vector2(min(a.x, a.x), min(b.y, b.y)); +} + +vector2 min(vector2 a, float b) +{ + return min(a, vector2(b, b)); +} + +vector2 fmod(vector2 a, vector2 b) +{ + return vector2(fmod(a.x, b.x), fmod(a.y, b.y)); +} + +vector2 fmod(vector2 a, float b) +{ + return fmod(a, vector2(b, b)); +} + +vector2 pow(vector2 in, vector2 amount) +{ + return vector2(pow(in.x, amount.x), pow(in.y, amount.y)); +} + +vector2 pow(vector2 in, float amount) +{ + return pow(in, vector2(amount, amount)); +} + +vector2 sign(vector2 a) +{ + return vector2(sign(a.x), sign(a.y)); +} + +vector2 sin(vector2 a) +{ + return vector2(sin(a.x), sin(a.y)); +} + +vector2 cos(vector2 a) +{ + return vector2(cos(a.x), cos(a.y)); +} + +vector2 tan(vector2 a) +{ + return vector2(tan(a.x), tan(a.y)); +} + +vector2 asin(vector2 a) +{ + return vector2(asin(a.x), asin(a.y)); +} + +vector2 acos(vector2 a) +{ + return vector2(acos(a.x), acos(a.y)); +} + +vector2 atan2(vector2 a, float f) +{ + return vector2(atan2(a.x, f), atan2(a.y, f)); +} + +vector2 atan2(vector2 a, vector2 b) +{ + return vector2(atan2(a.x, b.x), atan2(a.y, b.y)); +} diff --git a/intern/cycles/kernel/shaders/vector4.h b/intern/cycles/kernel/shaders/vector4.h new file mode 100644 index 00000000000..58e1b3c2e23 --- /dev/null +++ b/intern/cycles/kernel/shaders/vector4.h @@ -0,0 +1,327 @@ +// Open Shading Language : Copyright (c) 2009-2017 Sony Pictures Imageworks Inc., et al. +// https://github.com/imageworks/OpenShadingLanguage/blob/master/LICENSE + +#pragma once +#define VECTOR4_H + +// vector4 is a 4D vector +struct vector4 { + float x; + float y; + float z; + float w; +}; + +// +// For vector4, define math operators to match vector +// + +vector4 __operator__neg__(vector4 a) +{ + return vector4(-a.x, -a.y, -a.z, -a.w); +} + +vector4 __operator__add__(vector4 a, vector4 b) +{ + return vector4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); +} + +vector4 __operator__add__(vector4 a, int b) +{ + return a + vector4(b, b, b, b); +} + +vector4 __operator__add__(vector4 a, float b) +{ + return a + vector4(b, b, b, b); +} + +vector4 __operator__add__(int a, vector4 b) +{ + return vector4(a, a, a, a) + b; +} + +vector4 __operator__add__(float a, vector4 b) +{ + return vector4(a, a, a, a) + b; +} + +vector4 __operator__sub__(vector4 a, vector4 b) +{ + return vector4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); +} + +vector4 __operator__sub__(vector4 a, int b) +{ + return a - vector4(b, b, b, b); +} + +vector4 __operator__sub__(vector4 a, float b) +{ + return a - vector4(b, b, b, b); +} + +vector4 __operator__sub__(int a, vector4 b) +{ + return vector4(a, a, a, a) - b; +} + +vector4 __operator__sub__(float a, vector4 b) +{ + return vector4(a, a, a, a) - b; +} + +vector4 __operator__mul__(vector4 a, vector4 b) +{ + return vector4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); +} + +vector4 __operator__mul__(vector4 a, int b) +{ + return a * vector4(b, b, b, b); +} + +vector4 __operator__mul__(vector4 a, float b) +{ + return a * vector4(b, b, b, b); +} + +vector4 __operator__mul__(int a, vector4 b) +{ + return vector4(a, a, a, a) * b; +} + +vector4 __operator__mul__(float a, vector4 b) +{ + return vector4(a, a, a, a) * b; +} + +vector4 __operator__div__(vector4 a, vector4 b) +{ + return vector4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); +} + +vector4 __operator__div__(vector4 a, int b) +{ + float b_inv = 1 / b; + return a * vector4(b_inv, b_inv, b_inv, b_inv); +} + +vector4 __operator__div__(vector4 a, float b) +{ + float b_inv = 1 / b; + return a * vector4(b_inv, b_inv, b_inv, b_inv); +} + +vector4 __operator__div__(int a, vector4 b) +{ + return vector4(a, a, a, a) / b; +} + +vector4 __operator__div__(float a, vector4 b) +{ + return vector4(a, a, a, a) / b; +} + +int __operator__eq__(vector4 a, vector4 b) +{ + return (a.x == b.x) && (a.y == b.y) && (a.z == b.z) && (a.w == b.w); +} + +int __operator__ne__(vector4 a, vector4 b) +{ + return (a.x != b.x) || (a.y != b.y) || (a.z != b.z) || (a.w != b.w); +} + +// +// For vector4, define most of the stdosl functions to match vector +// + +vector4 abs(vector4 in) +{ + return vector4(abs(in.x), abs(in.y), abs(in.z), abs(in.w)); +} + +vector4 ceil(vector4 in) +{ + return vector4(ceil(in.x), ceil(in.y), ceil(in.z), ceil(in.w)); +} + +vector4 floor(vector4 in) +{ + return vector4(floor(in.x), floor(in.y), floor(in.z), floor(in.w)); +} + +vector4 sqrt(vector4 in) +{ + return vector4(sqrt(in.x), sqrt(in.y), sqrt(in.z), sqrt(in.w)); +} + +vector4 exp(vector4 in) +{ + return vector4(exp(in.x), exp(in.y), exp(in.z), exp(in.w)); +} + +vector4 log(vector4 in) +{ + return vector4(log(in.x), log(in.y), log(in.z), log(in.w)); +} + +vector4 log2(vector4 in) +{ + return vector4(log2(in.x), log2(in.y), log2(in.z), log2(in.w)); +} + +vector4 mix(vector4 value1, vector4 value2, float x) +{ + return vector4(mix(value1.x, value2.x, x), + mix(value1.y, value2.y, x), + mix(value1.z, value2.z, x), + mix(value1.w, value2.w, x)); +} + +vector vec4ToVec3(vector4 v) +{ + return vector(v.x, v.y, v.z) / v.w; +} + +float dot(vector4 a, vector4 b) +{ + return ((a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w)); +} + +float length(vector4 a) +{ + return sqrt(a.x * a.x + a.y * a.y + a.z * a.z + a.w * a.w); +} + +vector4 smoothstep(vector4 low, vector4 high, vector4 in) +{ + return vector4(smoothstep(low.x, high.x, in.x), + smoothstep(low.y, high.y, in.y), + smoothstep(low.z, high.z, in.z), + smoothstep(low.w, high.w, in.w)); +} + +vector4 smoothstep(float low, float high, vector4 in) +{ + return vector4(smoothstep(low, high, in.x), + smoothstep(low, high, in.y), + smoothstep(low, high, in.z), + smoothstep(low, high, in.w)); +} + +vector4 clamp(vector4 in, vector4 low, vector4 high) +{ + return vector4(clamp(in.x, low.x, high.x), + clamp(in.y, low.y, high.y), + clamp(in.z, low.z, high.z), + clamp(in.w, low.w, high.w)); +} + +vector4 clamp(vector4 in, float low, float high) +{ + return vector4(clamp(in.x, low, high), + clamp(in.y, low, high), + clamp(in.z, low, high), + clamp(in.w, low, high)); +} + +vector4 max(vector4 a, vector4 b) +{ + return vector4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w)); +} + +vector4 max(vector4 a, float b) +{ + return max(a, vector4(b, b, b, b)); +} + +vector4 normalize(vector4 a) +{ + return a / length(a); +} + +vector4 min(vector4 a, vector4 b) +{ + return vector4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w)); +} + +vector4 min(vector4 a, float b) +{ + return min(a, vector4(b, b, b, b)); +} + +vector4 fmod(vector4 a, vector4 b) +{ + return vector4(fmod(a.x, b.x), fmod(a.y, b.y), fmod(a.z, b.z), fmod(a.w, b.w)); +} + +vector4 fmod(vector4 a, float b) +{ + return fmod(a, vector4(b, b, b, b)); +} + +vector4 pow(vector4 in, vector4 amount) +{ + return vector4( + pow(in.x, amount.x), pow(in.y, amount.y), pow(in.z, amount.z), pow(in.w, amount.w)); +} + +vector4 pow(vector4 in, float amount) +{ + return vector4(pow(in.x, amount), pow(in.y, amount), pow(in.z, amount), pow(in.w, amount)); +} + +vector4 sign(vector4 a) +{ + return vector4(sign(a.x), sign(a.y), sign(a.z), sign(a.w)); +} + +vector4 sin(vector4 a) +{ + return vector4(sin(a.x), sin(a.y), sin(a.z), sin(a.w)); +} + +vector4 cos(vector4 a) +{ + return vector4(cos(a.x), cos(a.y), cos(a.z), cos(a.w)); +} + +vector4 tan(vector4 a) +{ + return vector4(tan(a.x), tan(a.y), tan(a.z), tan(a.w)); +} + +vector4 asin(vector4 a) +{ + return vector4(asin(a.x), asin(a.y), asin(a.z), asin(a.w)); +} + +vector4 acos(vector4 a) +{ + return vector4(acos(a.x), acos(a.y), acos(a.z), acos(a.w)); +} + +vector4 atan2(vector4 a, float f) +{ + return vector4(atan2(a.x, f), atan2(a.y, f), atan2(a.z, f), atan2(a.w, f)); +} + +vector4 atan2(vector4 a, vector4 b) +{ + return vector4(atan2(a.x, b.x), atan2(a.y, b.y), atan2(a.z, b.z), atan2(a.w, b.w)); +} + +vector4 transform(matrix M, vector4 p) +{ + return vector4(M[0][0] * p.x + M[0][1] * p.y + M[0][2] * p.z + M[0][2] * p.w, + M[1][0] * p.x + M[1][1] * p.y + M[1][2] * p.z + M[1][2] * p.w, + M[2][0] * p.x + M[2][1] * p.y + M[2][2] * p.z + M[2][2] * p.w, + M[3][0] * p.x + M[3][1] * p.y + M[3][2] * p.z + M[3][2] * p.w); +} + +vector4 transform(string fromspace, string tospace, vector4 p) +{ + return transform(matrix(fromspace, tospace), p); +} diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index ab8570618ab..ce651a1b5ff 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -158,10 +158,11 @@ CCL_NAMESPACE_END /* Nodes */ #include "kernel/svm/svm_noise.h" -#include "svm_texture.h" +#include "svm_fractal_noise.h" #include "kernel/svm/svm_color_util.h" #include "kernel/svm/svm_math_util.h" +#include "kernel/svm/svm_mapping_util.h" #include "kernel/svm/svm_attribute.h" #include "kernel/svm/svm_gradient.h" @@ -313,7 +314,7 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, svm_node_tex_image_box(kg, sd, stack, node); break; case NODE_TEX_NOISE: - svm_node_tex_noise(kg, sd, stack, node, &offset); + svm_node_tex_noise(kg, sd, stack, node.y, node.z, node.w, &offset); break; # endif /* __TEXTURES__ */ # ifdef __EXTRA_NODES__ @@ -405,8 +406,11 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, #endif /* NODES_GROUP(NODE_GROUP_LEVEL_1) */ #if NODES_GROUP(NODE_GROUP_LEVEL_2) + case NODE_TEXTURE_MAPPING: + svm_node_texture_mapping(kg, sd, stack, node.y, node.z, &offset); + break; case NODE_MAPPING: - svm_node_mapping(kg, sd, stack, node.y, node.z, &offset); + svm_node_mapping(kg, sd, stack, node.y, node.z, node.w, &offset); break; case NODE_MIN_MAX: svm_node_min_max(kg, sd, stack, node.y, node.z, &offset); diff --git a/intern/cycles/kernel/svm/svm_fractal_noise.h b/intern/cycles/kernel/svm/svm_fractal_noise.h new file mode 100644 index 00000000000..5b2e4a28fce --- /dev/null +++ b/intern/cycles/kernel/svm/svm_fractal_noise.h @@ -0,0 +1,131 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +CCL_NAMESPACE_BEGIN + +/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */ +ccl_device_noinline float fractal_noise_1d(float p, float octaves) +{ + float fscale = 1.0f; + float amp = 1.0f; + float sum = 0.0f; + octaves = clamp(octaves, 0.0f, 16.0f); + int n = float_to_int(octaves); + for (int i = 0; i <= n; i++) { + float t = noise_1d(fscale * p); + sum += t * amp; + amp *= 0.5f; + fscale *= 2.0f; + } + float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + float t = noise_1d(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0f - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */ +ccl_device_noinline float fractal_noise_2d(float2 p, float octaves) +{ + float fscale = 1.0f; + float amp = 1.0f; + float sum = 0.0f; + octaves = clamp(octaves, 0.0f, 16.0f); + int n = float_to_int(octaves); + for (int i = 0; i <= n; i++) { + float t = noise_2d(fscale * p); + sum += t * amp; + amp *= 0.5f; + fscale *= 2.0f; + } + float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + float t = noise_2d(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0f - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */ +ccl_device_noinline float fractal_noise_3d(float3 p, float octaves) +{ + float fscale = 1.0f; + float amp = 1.0f; + float sum = 0.0f; + octaves = clamp(octaves, 0.0f, 16.0f); + int n = float_to_int(octaves); + for (int i = 0; i <= n; i++) { + float t = noise_3d(fscale * p); + sum += t * amp; + amp *= 0.5f; + fscale *= 2.0f; + } + float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + float t = noise_3d(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0f - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +/* The fractal_noise_[1-4] functions are all exactly the same except for the input type. */ +ccl_device_noinline float fractal_noise_4d(float4 p, float octaves) +{ + float fscale = 1.0f; + float amp = 1.0f; + float sum = 0.0f; + octaves = clamp(octaves, 0.0f, 16.0f); + int n = float_to_int(octaves); + for (int i = 0; i <= n; i++) { + float t = noise_4d(fscale * p); + sum += t * amp; + amp *= 0.5f; + fscale *= 2.0f; + } + float rmd = octaves - floorf(octaves); + if (rmd != 0.0f) { + float t = noise_4d(fscale * p); + float sum2 = sum + t * amp; + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); + return (1.0f - rmd) * sum + rmd * sum2; + } + else { + sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); + return sum; + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_mapping.h b/intern/cycles/kernel/svm/svm_mapping.h index 998a29912d4..6e19c859e19 100644 --- a/intern/cycles/kernel/svm/svm_mapping.h +++ b/intern/cycles/kernel/svm/svm_mapping.h @@ -18,7 +18,33 @@ CCL_NAMESPACE_BEGIN /* Mapping Node */ -ccl_device void svm_node_mapping( +ccl_device void svm_node_mapping(KernelGlobals *kg, + ShaderData *sd, + float *stack, + uint type, + uint inputs_stack_offsets, + uint result_stack_offset, + int *offset) +{ + uint vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset; + svm_unpack_node_uchar4(inputs_stack_offsets, + &vector_stack_offset, + &location_stack_offset, + &rotation_stack_offset, + &scale_stack_offset); + + float3 vector = stack_load_float3(stack, vector_stack_offset); + float3 location = stack_load_float3(stack, location_stack_offset); + float3 rotation = stack_load_float3(stack, rotation_stack_offset); + float3 scale = stack_load_float3(stack, scale_stack_offset); + + float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale); + stack_store_float3(stack, result_stack_offset, result); +} + +/* Texture Mapping */ + +ccl_device void svm_node_texture_mapping( KernelGlobals *kg, ShaderData *sd, float *stack, uint vec_offset, uint out_offset, int *offset) { float3 v = stack_load_float3(stack, vec_offset); diff --git a/intern/cycles/kernel/svm/svm_mapping_util.h b/intern/cycles/kernel/svm/svm_mapping_util.h new file mode 100644 index 00000000000..ec2c84e0791 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_mapping_util.h @@ -0,0 +1,39 @@ +/* + * Copyright 2011-2014 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. + */ + +CCL_NAMESPACE_BEGIN + +ccl_device float3 +svm_mapping(NodeMappingType type, float3 vector, float3 location, float3 rotation, float3 scale) +{ + Transform rotationTransform = euler_to_transform(rotation); + switch (type) { + case NODE_MAPPING_TYPE_POINT: + return transform_direction(&rotationTransform, (vector * scale)) + location; + case NODE_MAPPING_TYPE_TEXTURE: + return safe_divide_float3_float3( + transform_direction_transposed(&rotationTransform, (vector - location)), scale); + case NODE_MAPPING_TYPE_VECTOR: + return transform_direction(&rotationTransform, (vector * scale)); + case NODE_MAPPING_TYPE_NORMAL: + return safe_normalize( + transform_direction(&rotationTransform, safe_divide_float3_float3(vector, scale))); + default: + return make_float3(0.0f, 0.0f, 0.0f); + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_musgrave.h b/intern/cycles/kernel/svm/svm_musgrave.h index 9291c7e7295..db87f04581f 100644 --- a/intern/cycles/kernel/svm/svm_musgrave.h +++ b/intern/cycles/kernel/svm/svm_musgrave.h @@ -37,14 +37,14 @@ ccl_device_noinline_cpu float noise_musgrave_fBm(float3 p, int i; for (i = 0; i < float_to_int(octaves); i++) { - value += snoise(p) * pwr; + value += snoise_3d(p) * pwr; pwr *= pwHL; p *= lacunarity; } rmd = octaves - floorf(octaves); if (rmd != 0.0f) - value += rmd * snoise(p) * pwr; + value += rmd * snoise_3d(p) * pwr; return value; } @@ -68,14 +68,14 @@ ccl_device_noinline_cpu float noise_musgrave_multi_fractal(float3 p, int i; for (i = 0; i < float_to_int(octaves); i++) { - value *= (pwr * snoise(p) + 1.0f); + value *= (pwr * snoise_3d(p) + 1.0f); pwr *= pwHL; p *= lacunarity; } rmd = octaves - floorf(octaves); if (rmd != 0.0f) - value *= (rmd * pwr * snoise(p) + 1.0f); /* correct? */ + value *= (rmd * pwr * snoise_3d(p) + 1.0f); /* correct? */ return value; } @@ -97,11 +97,11 @@ ccl_device_noinline_cpu float noise_musgrave_hetero_terrain( int i; /* first unscaled octave of function; later octaves are scaled */ - value = offset + snoise(p); + value = offset + snoise_3d(p); p *= lacunarity; for (i = 1; i < float_to_int(octaves); i++) { - increment = (snoise(p) + offset) * pwr * value; + increment = (snoise_3d(p) + offset) * pwr * value; value += increment; pwr *= pwHL; p *= lacunarity; @@ -109,7 +109,7 @@ ccl_device_noinline_cpu float noise_musgrave_hetero_terrain( rmd = octaves - floorf(octaves); if (rmd != 0.0f) { - increment = (snoise(p) + offset) * pwr * value; + increment = (snoise_3d(p) + offset) * pwr * value; value += rmd * increment; } @@ -132,7 +132,7 @@ ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal( float pwr = pwHL; int i; - result = snoise(p) + offset; + result = snoise_3d(p) + offset; weight = gain * result; p *= lacunarity; @@ -140,7 +140,7 @@ ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal( if (weight > 1.0f) weight = 1.0f; - signal = (snoise(p) + offset) * pwr; + signal = (snoise_3d(p) + offset) * pwr; pwr *= pwHL; result += weight * signal; weight *= gain * signal; @@ -149,7 +149,7 @@ ccl_device_noinline_cpu float noise_musgrave_hybrid_multi_fractal( rmd = octaves - floorf(octaves); if (rmd != 0.0f) - result += rmd * ((snoise(p) + offset) * pwr); + result += rmd * ((snoise_3d(p) + offset) * pwr); return result; } @@ -170,7 +170,7 @@ ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal( float pwr = pwHL; int i; - signal = offset - fabsf(snoise(p)); + signal = offset - fabsf(snoise_3d(p)); signal *= signal; result = signal; weight = 1.0f; @@ -178,7 +178,7 @@ ccl_device_noinline_cpu float noise_musgrave_ridged_multi_fractal( for (i = 1; i < float_to_int(octaves); i++) { p *= lacunarity; weight = saturate(signal * gain); - signal = offset - fabsf(snoise(p)); + signal = offset - fabsf(snoise_3d(p)); signal *= signal; signal *= weight; result += signal * pwr; diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h index dd375af27e5..35b74fb4b3e 100644 --- a/intern/cycles/kernel/svm/svm_noise.h +++ b/intern/cycles/kernel/svm/svm_noise.h @@ -32,246 +32,566 @@ CCL_NAMESPACE_BEGIN -#ifdef __KERNEL_SSE2__ -ccl_device_inline ssei quick_floor_sse(const ssef &x) -{ - ssei b = truncatei(x); - ssei isneg = cast((x < ssef(0.0f)).m128); - return b + isneg; // unsaturated add 0xffffffff is the same as subtract -1 -} -#endif - -#ifdef __KERNEL_SSE2__ -ccl_device_inline ssei hash_sse(const ssei &kx, const ssei &ky, const ssei &kz) -{ -# define rot(x, k) (((x) << (k)) | (srl(x, 32 - (k)))) -# define xor_rot(a, b, c) \ - do { \ - a = a ^ b; \ - a = a - rot(b, c); \ - } while (0) - - uint len = 3; - ssei magic = ssei(0xdeadbeef + (len << 2) + 13); - ssei a = magic + kx; - ssei b = magic + ky; - ssei c = magic + kz; - - xor_rot(c, b, 14); - xor_rot(a, c, 11); - xor_rot(b, a, 25); - xor_rot(c, b, 16); - xor_rot(a, c, 4); - xor_rot(b, a, 14); - xor_rot(c, b, 24); - - return c; -# undef rot -# undef xor_rot -} -#endif +/* **** Perlin Noise **** */ -#if 0 // unused -ccl_device int imod(int a, int b) +ccl_device float fade(float t) { - a %= b; - return a < 0 ? a + b : a; + return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); } -ccl_device uint phash(int kx, int ky, int kz, int3 p) +ccl_device_inline float negate_if(float val, int condition) { - return hash(imod(kx, p.x), imod(ky, p.y), imod(kz, p.z)); + return (condition) ? -val : val; } -#endif -#ifndef __KERNEL_SSE2__ -ccl_device float floorfrac(float x, int *i) +ccl_device float grad1(int hash, float x) { - *i = quick_floor_to_int(x); - return x - *i; + int h = hash & 15; + float g = 1 + (h & 7); + return negate_if(g, h & 8) * x; } -#else -ccl_device_inline ssef floorfrac_sse(const ssef &x, ssei *i) + +ccl_device_noinline_cpu float perlin_1d(float x) { - *i = quick_floor_sse(x); - return x - ssef(*i); + int X; + float fx = floorfrac(x, &X); + float u = fade(fx); + + return mix(grad1(hash_uint(X), fx), grad1(hash_uint(X + 1), fx - 1.0f), u); } -#endif +/* 2D, 3D, and 4D noise can be accelerated using SSE, so we first check if + * SSE is supported, that is, if __KERNEL_SSE2__ is defined. If it is not + * supported, we do a standard implementation, but if it is supported, we + * do an implementation using SSE intrinsics. + */ #ifndef __KERNEL_SSE2__ -ccl_device float fade(float t) + +/* ** Standard Implementation ** */ + +/* Bilinear Interpolation: + * + * v2 v3 + * @ + + + + @ y + * + + ^ + * + + | + * + + | + * @ + + + + @ @------> x + * v0 v1 + * + */ +ccl_device float bi_mix(float v0, float v1, float v2, float v3, float x, float y) { - return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f); + float x1 = 1.0f - x; + return (1.0f - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x); } -#else -ccl_device_inline ssef fade_sse(const ssef *t) + +/* Trilinear Interpolation: + * + * v6 v7 + * @ + + + + + + @ + * +\ +\ + * + \ + \ + * + \ + \ + * + \ v4 + \ v5 + * + @ + + + +++ + @ z + * + + + + y ^ + * v2 @ + +++ + + + @ v3 + \ | + * \ + \ + \ | + * \ + \ + \| + * \ + \ + +---------> x + * \+ \+ + * @ + + + + + + @ + * v0 v1 + */ +ccl_device float tri_mix(float v0, + float v1, + float v2, + float v3, + float v4, + float v5, + float v6, + float v7, + float x, + float y, + float z) { - ssef a = madd(*t, ssef(6.0f), ssef(-15.0f)); - ssef b = madd(*t, a, ssef(10.0f)); - return ((*t) * (*t)) * ((*t) * b); + float x1 = 1.0f - x; + float y1 = 1.0f - y; + float z1 = 1.0f - z; + return z1 * (y1 * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x)) + + z * (y1 * (v4 * x1 + v5 * x) + y * (v6 * x1 + v7 * x)); } -#endif -#ifndef __KERNEL_SSE2__ -ccl_device float nerp(float t, float a, float b) +ccl_device float quad_mix(float v0, + float v1, + float v2, + float v3, + float v4, + float v5, + float v6, + float v7, + float v8, + float v9, + float v10, + float v11, + float v12, + float v13, + float v14, + float v15, + float x, + float y, + float z, + float w) { - return (1.0f - t) * a + t * b; + return mix(tri_mix(v0, v1, v2, v3, v4, v5, v6, v7, x, y, z), + tri_mix(v8, v9, v10, v11, v12, v13, v14, v15, x, y, z), + w); } -#else -ccl_device_inline ssef nerp_sse(const ssef &t, const ssef &a, const ssef &b) + +ccl_device float grad2(int hash, float x, float y) { - ssef x1 = (ssef(1.0f) - t) * a; - return madd(t, b, x1); + int h = hash & 7; + float u = h < 4 ? x : y; + float v = 2.0f * (h < 4 ? y : x); + return negate_if(u, h & 1) + negate_if(v, h & 2); } -#endif -#ifndef __KERNEL_SSE2__ -ccl_device float grad(int hash, float x, float y, float z) +ccl_device float grad3(int hash, float x, float y, float z) { - // use vectors pointing to the edges of the cube int h = hash & 15; float u = h < 8 ? x : y; - float vt = ((h == 12) | (h == 14)) ? x : z; + float vt = ((h == 12) || (h == 14)) ? x : z; float v = h < 4 ? y : vt; - return ((h & 1) ? -u : u) + ((h & 2) ? -v : v); + return negate_if(u, h & 1) + negate_if(v, h & 2); } -#else -ccl_device_inline ssef grad_sse(const ssei &hash, const ssef &x, const ssef &y, const ssef &z) -{ - ssei c1 = ssei(1); - ssei c2 = ssei(2); - ssei h = hash & ssei(15); // h = hash & 15 +ccl_device float grad4(int hash, float x, float y, float z, float w) +{ + int h = hash & 31; + float u = h < 24 ? x : y; + float v = h < 16 ? y : z; + float s = h < 8 ? z : w; + return negate_if(u, h & 1) + negate_if(v, h & 2) + negate_if(s, h & 4); +} - sseb case_ux = h < ssei(8); // 0xffffffff if h < 8 else 0 +ccl_device_noinline_cpu float perlin_2d(float x, float y) +{ + int X; + int Y; - ssef u = select(case_ux, x, y); // u = h<8 ? x : y + float fx = floorfrac(x, &X); + float fy = floorfrac(y, &Y); - sseb case_vy = h < ssei(4); // 0xffffffff if h < 4 else 0 + float u = fade(fx); + float v = fade(fy); - sseb case_h12 = h == ssei(12); // 0xffffffff if h == 12 else 0 - sseb case_h14 = h == ssei(14); // 0xffffffff if h == 14 else 0 + float r = bi_mix(grad2(hash_uint2(X, Y), fx, fy), + grad2(hash_uint2(X + 1, Y), fx - 1.0f, fy), + grad2(hash_uint2(X, Y + 1), fx, fy - 1.0f), + grad2(hash_uint2(X + 1, Y + 1), fx - 1.0f, fy - 1.0f), + u, + v); - sseb case_vx = case_h12 | case_h14; // 0xffffffff if h == 12 or h == 14 else 0 + return r; +} - ssef v = select(case_vy, y, select(case_vx, x, z)); // v = h<4 ? y : h == 12 || h == 14 ? x : z +ccl_device_noinline_cpu float perlin_3d(float x, float y, float z) +{ + int X; + int Y; + int Z; - ssei case_uneg = (h & c1) << 31; // 1<<31 if h&1 else 0 - ssef case_uneg_mask = cast(case_uneg); // -0.0 if h&1 else +0.0 - ssef ru = u ^ case_uneg_mask; // -u if h&1 else u (copy float sign) + float fx = floorfrac(x, &X); + float fy = floorfrac(y, &Y); + float fz = floorfrac(z, &Z); - ssei case_vneg = (h & c2) << 30; // 2<<30 if h&2 else 0 - ssef case_vneg_mask = cast(case_vneg); // -0.0 if h&2 else +0.0 - ssef rv = v ^ case_vneg_mask; // -v if h&2 else v (copy float sign) + float u = fade(fx); + float v = fade(fy); + float w = fade(fz); - ssef r = ru + rv; // ((h&1) ? -u : u) + ((h&2) ? -v : v) + float r = tri_mix(grad3(hash_uint3(X, Y, Z), fx, fy, fz), + grad3(hash_uint3(X + 1, Y, Z), fx - 1.0f, fy, fz), + grad3(hash_uint3(X, Y + 1, Z), fx, fy - 1.0f, fz), + grad3(hash_uint3(X + 1, Y + 1, Z), fx - 1.0f, fy - 1.0f, fz), + grad3(hash_uint3(X, Y, Z + 1), fx, fy, fz - 1.0f), + grad3(hash_uint3(X + 1, Y, Z + 1), fx - 1.0f, fy, fz - 1.0f), + grad3(hash_uint3(X, Y + 1, Z + 1), fx, fy - 1.0f, fz - 1.0f), + grad3(hash_uint3(X + 1, Y + 1, Z + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f), + u, + v, + w); return r; } -#endif -#ifndef __KERNEL_SSE2__ -ccl_device float scale3(float result) -{ - return 0.9820f * result; -} -#else -ccl_device_inline ssef scale3_sse(const ssef &result) -{ - return ssef(0.9820f) * result; -} -#endif - -#ifndef __KERNEL_SSE2__ -ccl_device_noinline_cpu float perlin(float x, float y, float z) +ccl_device_noinline_cpu float perlin_4d(float x, float y, float z, float w) { int X; - float fx = floorfrac(x, &X); int Y; - float fy = floorfrac(y, &Y); int Z; + int W; + + float fx = floorfrac(x, &X); + float fy = floorfrac(y, &Y); float fz = floorfrac(z, &Z); + float fw = floorfrac(w, &W); float u = fade(fx); float v = fade(fy); - float w = fade(fz); + float t = fade(fz); + float s = fade(fw); + + float r = quad_mix( + grad4(hash_uint4(X, Y, Z, W), fx, fy, fz, fw), + grad4(hash_uint4(X + 1, Y, Z, W), fx - 1.0f, fy, fz, fw), + grad4(hash_uint4(X, Y + 1, Z, W), fx, fy - 1.0f, fz, fw), + grad4(hash_uint4(X + 1, Y + 1, Z, W), fx - 1.0f, fy - 1.0f, fz, fw), + grad4(hash_uint4(X, Y, Z + 1, W), fx, fy, fz - 1.0f, fw), + grad4(hash_uint4(X + 1, Y, Z + 1, W), fx - 1.0f, fy, fz - 1.0f, fw), + grad4(hash_uint4(X, Y + 1, Z + 1, W), fx, fy - 1.0f, fz - 1.0f, fw), + grad4(hash_uint4(X + 1, Y + 1, Z + 1, W), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw), + grad4(hash_uint4(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0f), + grad4(hash_uint4(X + 1, Y, Z, W + 1), fx - 1.0f, fy, fz, fw - 1.0f), + grad4(hash_uint4(X, Y + 1, Z, W + 1), fx, fy - 1.0f, fz, fw - 1.0f), + grad4(hash_uint4(X + 1, Y + 1, Z, W + 1), fx - 1.0f, fy - 1.0f, fz, fw - 1.0f), + grad4(hash_uint4(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0f, fw - 1.0f), + grad4(hash_uint4(X + 1, Y, Z + 1, W + 1), fx - 1.0f, fy, fz - 1.0f, fw - 1.0f), + grad4(hash_uint4(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0f, fz - 1.0f, fw - 1.0f), + grad4(hash_uint4(X + 1, Y + 1, Z + 1, W + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f, fw - 1.0f), + u, + v, + t, + s); - float result; - - result = nerp( - w, - nerp(v, - nerp(u, - grad(hash_uint3(X, Y, Z), fx, fy, fz), - grad(hash_uint3(X + 1, Y, Z), fx - 1.0f, fy, fz)), - nerp(u, - grad(hash_uint3(X, Y + 1, Z), fx, fy - 1.0f, fz), - grad(hash_uint3(X + 1, Y + 1, Z), fx - 1.0f, fy - 1.0f, fz))), - nerp(v, - nerp(u, - grad(hash_uint3(X, Y, Z + 1), fx, fy, fz - 1.0f), - grad(hash_uint3(X + 1, Y, Z + 1), fx - 1.0f, fy, fz - 1.0f)), - nerp(u, - grad(hash_uint3(X, Y + 1, Z + 1), fx, fy - 1.0f, fz - 1.0f), - grad(hash_uint3(X + 1, Y + 1, Z + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f)))); - float r = scale3(result); - - /* can happen for big coordinates, things even out to 0.0 then anyway */ - return (isfinite(r)) ? r : 0.0f; + return r; } + #else -ccl_device_noinline float perlin(float x, float y, float z) + +/* ** SSE Implementation ** */ + +/* SSE Bilinear Interpolation: + * + * The function takes two ssef inputs: + * - p : Contains the values at the points (v0, v1, v2, v3). + * - f : Contains the values (x, y, _, _). The third and fourth values are unused. + * + * The interpolation is done in two steps: + * 1. Interpolate (v0, v1) and (v2, v3) along the x axis to get g (g0, g1). + * (v2, v3) is generated by moving v2 and v3 to the first and second + * places of the ssef using the shuffle mask <2, 3, 2, 3>. The third and + * fourth values are unused. + * 2. Interplate g0 and g1 along the y axis to get the final value. + * g1 is generated by populating an ssef with the second value of g. + * Only the first value is important in the final ssef. + * + * v1 v3 g1 + * @ + + + + @ @ y + * + + (1) + (2) ^ + * + + ---> + ---> final | + * + + + | + * @ + + + + @ @ @------> x + * v0 v2 g0 + * + */ +ccl_device_inline ssef bi_mix(ssef p, ssef f) +{ + ssef g = mix(p, shuffle<2, 3, 2, 3>(p), shuffle<0>(f)); + return mix(g, shuffle<1>(g), shuffle<1>(f)); +} + +/* SSE Trilinear Interpolation: + * + * The function takes three ssef inputs: + * - p : Contains the values at the points (v0, v1, v2, v3). + * - q : Contains the values at the points (v4, v5, v6, v7). + * - f : Contains the values (x, y, z, _). The fourth value is unused. + * + * The interpolation is done in three steps: + * 1. Interpolate p and q along the x axis to get s (s0, s1, s2, s3). + * 2. Interpolate (s0, s1) and (s2, s3) along the y axis to get g (g0, g1). + * (s2, s3) is generated by moving v2 and v3 to the first and second + * places of the ssef using the shuffle mask <2, 3, 2, 3>. The third and + * fourth values are unused. + * 3. Interplate g0 and g1 along the z axis to get the final value. + * g1 is generated by populating an ssef with the second value of g. + * Only the first value is important in the final ssef. + * + * v3 v7 + * @ + + + + + + @ s3 @ + * +\ +\ +\ + * + \ + \ + \ + * + \ + \ + \ g1 + * + \ v1 + \ v5 + \ s1 @ + * + @ + + + +++ + @ + @ + z + * + + + + (1) + + (2) + (3) y ^ + * v2 @ + +++ + + + @ v6 + ---> s2 @ + ---> + ---> final \ | + * \ + \ + \ + + \ | + * \ + \ + \ + + \| + * \ + \ + \ + @ +---------> x + * \+ \+ \+ g0 + * @ + + + + + + @ @ + * v0 v4 s0 + */ +ccl_device_inline ssef tri_mix(ssef p, ssef q, ssef f) +{ + ssef s = mix(p, q, shuffle<0>(f)); + ssef g = mix(s, shuffle<2, 3, 2, 3>(s), shuffle<1>(f)); + return mix(g, shuffle<1>(g), shuffle<2>(f)); +} + +/* SSE Quadrilinear Interpolation: + * + * Quadrilinear interpolation is as simple as a linear interpolation + * between two trilinear interpolations. + * + */ +ccl_device_inline ssef quad_mix(ssef p, ssef q, ssef r, ssef s, ssef f) +{ + return mix(tri_mix(p, q, f), tri_mix(r, s, f), shuffle<3>(f)); +} + +ccl_device_inline ssef fade(const ssef &t) +{ + ssef a = madd(t, 6.0f, -15.0f); + ssef b = madd(t, a, 10.0f); + return (t * t) * (t * b); +} + +/* Negate val if the nth bit of h is 1. */ +# define negate_if_nth_bit(val, h, n) ((val) ^ cast(((h) & (1 << (n))) << (31 - (n)))) + +ccl_device_inline ssef grad(const ssei &hash, const ssef &x, const ssef &y) +{ + ssei h = hash & 7; + ssef u = select(h < 4, x, y); + ssef v = 2.0f * select(h < 4, y, x); + return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1); +} + +ccl_device_inline ssef grad(const ssei &hash, const ssef &x, const ssef &y, const ssef &z) +{ + ssei h = hash & 15; + ssef u = select(h < 8, x, y); + ssef vt = select((h == 12) | (h == 14), x, z); + ssef v = select(h < 4, y, vt); + return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1); +} + +ccl_device_inline ssef +grad(const ssei &hash, const ssef &x, const ssef &y, const ssef &z, const ssef &w) +{ + ssei h = hash & 31; + ssef u = select(h < 24, x, y); + ssef v = select(h < 16, y, z); + ssef s = select(h < 8, z, w); + return negate_if_nth_bit(u, h, 0) + negate_if_nth_bit(v, h, 1) + negate_if_nth_bit(s, h, 2); +} + +/* We use SSE to compute and interpolate 4 gradients at once: + * + * Point Offset from v0 + * v0 (0, 0) + * v1 (0, 1) + * v2 (1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(V, V + 1)) + * v3 (1, 1) ^ + * | |__________| (0, 0, 1, 1) = shuffle<0, 0, 0, 0>(V, V + 1) + * | ^ + * |__________________________| + * + */ +ccl_device_noinline float perlin_2d(float x, float y) +{ + ssei XY; + ssef fxy = floorfrac(ssef(x, y, 0.0f, 0.0f), &XY); + ssef uv = fade(fxy); + + ssei XY1 = XY + 1; + ssei X = shuffle<0, 0, 0, 0>(XY, XY1); + ssei Y = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(XY, XY1)); + + ssei h = hash_ssei2(X, Y); + + ssef fxy1 = fxy - 1.0f; + ssef fx = shuffle<0, 0, 0, 0>(fxy, fxy1); + ssef fy = shuffle<0, 2, 0, 2>(shuffle<1, 1, 1, 1>(fxy, fxy1)); + + ssef g = grad(h, fx, fy); + + return extract<0>(bi_mix(g, uv)); +} + +/* We use SSE to compute and interpolate 4 gradients at once. Since we have 8 + * gradients in 3D, we need to compute two sets of gradients at the points: + * + * Point Offset from v0 + * v0 (0, 0, 0) + * v1 (0, 0, 1) + * v2 (0, 1, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1)) + * v3 (0, 1, 1) ^ + * | |__________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1) + * | ^ + * |__________________________| + * + * Point Offset from v0 + * v4 (1, 0, 0) + * v5 (1, 0, 1) + * v6 (1, 1, 0) + * v7 (1, 1, 1) + * + */ +ccl_device_noinline float perlin_3d(float x, float y, float z) { - ssef xyz = ssef(x, y, z, 0.0f); ssei XYZ; + ssef fxyz = floorfrac(ssef(x, y, z, 0.0f), &XYZ); + ssef uvw = fade(fxyz); - ssef fxyz = floorfrac_sse(xyz, &XYZ); + ssei XYZ1 = XYZ + 1; + ssei Y = shuffle<1, 1, 1, 1>(XYZ, XYZ1); + ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZ, XYZ1)); - ssef uvw = fade_sse(&fxyz); - ssef u = shuffle<0>(uvw), v = shuffle<1>(uvw), w = shuffle<2>(uvw); + ssei h1 = hash_ssei3(shuffle<0>(XYZ), Y, Z); + ssei h2 = hash_ssei3(shuffle<0>(XYZ1), Y, Z); - ssei XYZ_ofc = XYZ + ssei(1); - ssei vdy = shuffle<1, 1, 1, 1>(XYZ, XYZ_ofc); // +0, +0, +1, +1 - ssei vdz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZ, XYZ_ofc)); // +0, +1, +0, +1 + ssef fxyz1 = fxyz - 1.0f; + ssef fy = shuffle<1, 1, 1, 1>(fxyz, fxyz1); + ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyz, fxyz1)); - ssei h1 = hash_sse(shuffle<0>(XYZ), vdy, vdz); // hash directions 000, 001, 010, 011 - ssei h2 = hash_sse(shuffle<0>(XYZ_ofc), vdy, vdz); // hash directions 100, 101, 110, 111 + ssef g1 = grad(h1, shuffle<0>(fxyz), fy, fz); + ssef g2 = grad(h2, shuffle<0>(fxyz1), fy, fz); - ssef fxyz_ofc = fxyz - ssef(1.0f); - ssef vfy = shuffle<1, 1, 1, 1>(fxyz, fxyz_ofc); - ssef vfz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyz, fxyz_ofc)); + return extract<0>(tri_mix(g1, g2, uvw)); +} - ssef g1 = grad_sse(h1, shuffle<0>(fxyz), vfy, vfz); - ssef g2 = grad_sse(h2, shuffle<0>(fxyz_ofc), vfy, vfz); - ssef n1 = nerp_sse(u, g1, g2); +/* We use SSE to compute and interpolate 4 gradients at once. Since we have 16 + * gradients in 4D, we need to compute four sets of gradients at the points: + * + * Point Offset from v0 + * v0 (0, 0, 0, 0) + * v1 (0, 0, 1, 0) + * v2 (0, 1, 0, 0) (0, 1, 0, 1) = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(V, V + 1)) + * v3 (0, 1, 1, 0) ^ + * | |________| (0, 0, 1, 1) = shuffle<1, 1, 1, 1>(V, V + 1) + * | ^ + * |_______________________| + * + * Point Offset from v0 + * v4 (1, 0, 0, 0) + * v5 (1, 0, 1, 0) + * v6 (1, 1, 0, 0) + * v7 (1, 1, 1, 0) + * + * Point Offset from v0 + * v8 (0, 0, 0, 1) + * v9 (0, 0, 1, 1) + * v10 (0, 1, 0, 1) + * v11 (0, 1, 1, 1) + * + * Point Offset from v0 + * v12 (1, 0, 0, 1) + * v13 (1, 0, 1, 1) + * v14 (1, 1, 0, 1) + * v15 (1, 1, 1, 1) + * + */ +ccl_device_noinline float perlin_4d(float x, float y, float z, float w) +{ + ssei XYZW; + ssef fxyzw = floorfrac(ssef(x, y, z, w), &XYZW); + ssef uvws = fade(fxyzw); - ssef n1_half = shuffle<2, 3, 2, 3>(n1); // extract 2 floats to a separate vector - ssef n2 = nerp_sse( - v, n1, n1_half); // process nerp([a, b, _, _], [c, d, _, _]) -> [a', b', _, _] + ssei XYZW1 = XYZW + 1; + ssei Y = shuffle<1, 1, 1, 1>(XYZW, XYZW1); + ssei Z = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(XYZW, XYZW1)); - ssef n2_second = shuffle<1>(n2); // extract b to a separate vector - ssef result = nerp_sse( - w, n2, n2_second); // process nerp([a', _, _, _], [b', _, _, _]) -> [a'', _, _, _] + ssei h1 = hash_ssei4(shuffle<0>(XYZW), Y, Z, shuffle<3>(XYZW)); + ssei h2 = hash_ssei4(shuffle<0>(XYZW1), Y, Z, shuffle<3>(XYZW)); - ssef r = scale3_sse(result); + ssei h3 = hash_ssei4(shuffle<0>(XYZW), Y, Z, shuffle<3>(XYZW1)); + ssei h4 = hash_ssei4(shuffle<0>(XYZW1), Y, Z, shuffle<3>(XYZW1)); - ssef infmask = cast(ssei(0x7f800000)); - ssef rinfmask = ((r & infmask) == infmask).m128; // 0xffffffff if r is inf/-inf/nan else 0 - ssef rfinite = andnot(rinfmask, r); // 0 if r is inf/-inf/nan else r - return extract<0>(rfinite); + ssef fxyzw1 = fxyzw - 1.0f; + ssef fy = shuffle<1, 1, 1, 1>(fxyzw, fxyzw1); + ssef fz = shuffle<0, 2, 0, 2>(shuffle<2, 2, 2, 2>(fxyzw, fxyzw1)); + + ssef g1 = grad(h1, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw)); + ssef g2 = grad(h2, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw)); + + ssef g3 = grad(h3, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw1)); + ssef g4 = grad(h4, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw1)); + + return extract<0>(quad_mix(g1, g2, g3, g4, uvws)); } #endif -/* perlin noise in range 0..1 */ -ccl_device float noise(float3 p) +/* Remap the output of noise to a predictable range [-1, 1]. + * The scale values were computed experimentally by the OSL developers. + */ + +ccl_device_inline float noise_scale1(float result) +{ + return 0.2500f * result; +} + +ccl_device_inline float noise_scale2(float result) +{ + return 0.6616f * result; +} + +ccl_device_inline float noise_scale3(float result) +{ + return 0.9820f * result; +} + +ccl_device_inline float noise_scale4(float result) +{ + return 0.8344f * result; +} + +/* Safe Signed And Unsigned Noise */ + +ccl_device_inline float snoise_1d(float p) +{ + float r = perlin_1d(p); + return isinf(r) ? 0.0f : noise_scale1(r); +} + +ccl_device_inline float noise_1d(float p) +{ + return 0.5f * snoise_1d(p) + 0.5f; +} + +ccl_device_inline float snoise_2d(float2 p) +{ + float r = perlin_2d(p.x, p.y); + return isinf(r) ? 0.0f : noise_scale2(r); +} + +ccl_device_inline float noise_2d(float2 p) +{ + return 0.5f * snoise_2d(p) + 0.5f; +} + +ccl_device_inline float snoise_3d(float3 p) +{ + float r = perlin_3d(p.x, p.y, p.z); + return isinf(r) ? 0.0f : noise_scale3(r); +} + +ccl_device_inline float noise_3d(float3 p) +{ + return 0.5f * snoise_3d(p) + 0.5f; +} + +ccl_device_inline float snoise_4d(float4 p) { - float r = perlin(p.x, p.y, p.z); - return 0.5f * r + 0.5f; + float r = perlin_4d(p.x, p.y, p.z, p.w); + return isinf(r) ? 0.0f : noise_scale4(r); } -/* perlin noise in range -1..1 */ -ccl_device float snoise(float3 p) +ccl_device_inline float noise_4d(float4 p) { - return perlin(p.x, p.y, p.z); + return 0.5f * snoise_4d(p) + 0.5f; } /* cell noise */ @@ -293,7 +613,7 @@ ccl_device float3 cellnoise3(float3 p) ssei ip_yxz = shuffle<1, 0, 2, 3>(ssei(ip.m128)); ssei ip_xyy = shuffle<0, 1, 1, 3>(ssei(ip.m128)); ssei ip_zzx = shuffle<2, 2, 0, 3>(ssei(ip.m128)); - ssei bits = hash_sse(ip_xyy, ip_yxz, ip_zzx); + ssei bits = hash_ssei3(ip_xyy, ip_yxz, ip_zzx); return float3(uint32_to_float(bits) * ssef(1.0f / (float)0xFFFFFFFF)); #endif } diff --git a/intern/cycles/kernel/svm/svm_noisetex.h b/intern/cycles/kernel/svm/svm_noisetex.h index 91dc11691e6..c5a1e43a729 100644 --- a/intern/cycles/kernel/svm/svm_noisetex.h +++ b/intern/cycles/kernel/svm/svm_noisetex.h @@ -16,44 +16,172 @@ CCL_NAMESPACE_BEGIN -/* Noise */ +/* The following offset functions generate random offsets to be added to texture + * coordinates to act as a seed since the noise functions don't have seed values. + * A seed value is needed for generating distortion textures and color outputs. + * The offset's components are in the range [100, 200], not too high to cause + * bad precision and not to small to be noticeable. We use float seed because + * OSL only support float hashes. + */ + +ccl_device_inline float random_float_offset(float seed) +{ + return 100.0f + hash_float_to_float(seed) * 100.0f; +} + +ccl_device_inline float2 random_float2_offset(float seed) +{ + return make_float2(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f, + 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f); +} -ccl_device void svm_node_tex_noise( - KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) +ccl_device_inline float3 random_float3_offset(float seed) { - uint co_offset, scale_offset, detail_offset, distortion_offset, fac_offset, color_offset; + return make_float3(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f, + 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f, + 100.0f + hash_float2_to_float(make_float2(seed, 2.0f)) * 100.0f); +} - svm_unpack_node_uchar4(node.y, &co_offset, &scale_offset, &detail_offset, &distortion_offset); - svm_unpack_node_uchar2(node.z, &color_offset, &fac_offset); +ccl_device_inline float4 random_float4_offset(float seed) +{ + return make_float4(100.0f + hash_float2_to_float(make_float2(seed, 0.0f)) * 100.0f, + 100.0f + hash_float2_to_float(make_float2(seed, 1.0f)) * 100.0f, + 100.0f + hash_float2_to_float(make_float2(seed, 2.0f)) * 100.0f, + 100.0f + hash_float2_to_float(make_float2(seed, 3.0f)) * 100.0f); +} - uint4 node2 = read_node(kg, offset); +ccl_device void noise_texture_1d( + float co, float detail, float distortion, bool color_is_needed, float *value, float3 *color) +{ + float p = co; + if (distortion != 0.0f) { + p += noise_1d(p + random_float_offset(0.0f)) * distortion; + } + + *value = fractal_noise_1d(p, detail); + if (color_is_needed) { + *color = make_float3(*value, + fractal_noise_1d(p + random_float_offset(1.0f), detail), + fractal_noise_1d(p + random_float_offset(2.0f), detail)); + } +} + +ccl_device void noise_texture_2d( + float2 co, float detail, float distortion, bool color_is_needed, float *value, float3 *color) +{ + float2 p = co; + if (distortion != 0.0f) { + p += make_float2(noise_2d(p + random_float2_offset(0.0f)) * distortion, + noise_2d(p + random_float2_offset(1.0f)) * distortion); + } - float scale = stack_load_float_default(stack, scale_offset, node2.x); - float detail = stack_load_float_default(stack, detail_offset, node2.y); - float distortion = stack_load_float_default(stack, distortion_offset, node2.z); - float3 p = stack_load_float3(stack, co_offset) * scale; - int hard = 0; + *value = fractal_noise_2d(p, detail); + if (color_is_needed) { + *color = make_float3(*value, + fractal_noise_2d(p + random_float2_offset(2.0f), detail), + fractal_noise_2d(p + random_float2_offset(3.0f), detail)); + } +} +ccl_device void noise_texture_3d( + float3 co, float detail, float distortion, bool color_is_needed, float *value, float3 *color) +{ + float3 p = co; if (distortion != 0.0f) { - float3 r, offset = make_float3(13.5f, 13.5f, 13.5f); + p += make_float3(noise_3d(p + random_float3_offset(0.0f)) * distortion, + noise_3d(p + random_float3_offset(1.0f)) * distortion, + noise_3d(p + random_float3_offset(2.0f)) * distortion); + } - r.x = noise(p + offset) * distortion; - r.y = noise(p) * distortion; - r.z = noise(p - offset) * distortion; + *value = fractal_noise_3d(p, detail); + if (color_is_needed) { + *color = make_float3(*value, + fractal_noise_3d(p + random_float3_offset(3.0f), detail), + fractal_noise_3d(p + random_float3_offset(4.0f), detail)); + } +} - p += r; +ccl_device void noise_texture_4d( + float4 co, float detail, float distortion, bool color_is_needed, float *value, float3 *color) +{ + float4 p = co; + if (distortion != 0.0f) { + p += make_float4(noise_4d(p + random_float4_offset(0.0f)) * distortion, + noise_4d(p + random_float4_offset(1.0f)) * distortion, + noise_4d(p + random_float4_offset(2.0f)) * distortion, + noise_4d(p + random_float4_offset(3.0f)) * distortion); } - float f = noise_turbulence(p, detail, hard); + *value = fractal_noise_4d(p, detail); + if (color_is_needed) { + *color = make_float3(*value, + fractal_noise_4d(p + random_float4_offset(4.0f), detail), + fractal_noise_4d(p + random_float4_offset(5.0f), detail)); + } +} + +ccl_device void svm_node_tex_noise(KernelGlobals *kg, + ShaderData *sd, + float *stack, + uint dimensions, + uint offsets1, + uint offsets2, + int *offset) +{ + uint vector_stack_offset, w_stack_offset, scale_stack_offset, detail_stack_offset; + uint distortion_stack_offset, value_stack_offset, color_stack_offset; + + svm_unpack_node_uchar4( + offsets1, &vector_stack_offset, &w_stack_offset, &scale_stack_offset, &detail_stack_offset); + svm_unpack_node_uchar3( + offsets2, &distortion_stack_offset, &value_stack_offset, &color_stack_offset); + + uint4 defaults = read_node(kg, offset); + + float3 vector = stack_load_float3(stack, vector_stack_offset); + float w = stack_load_float_default(stack, w_stack_offset, defaults.x); + float scale = stack_load_float_default(stack, scale_stack_offset, defaults.y); + float detail = stack_load_float_default(stack, detail_stack_offset, defaults.z); + float distortion = stack_load_float_default(stack, distortion_stack_offset, defaults.w); + + vector *= scale; + w *= scale; + + float value; + float3 color; + switch (dimensions) { + case 1: + noise_texture_1d(w, detail, distortion, stack_valid(color_stack_offset), &value, &color); + break; + case 2: + noise_texture_2d(make_float2(vector.x, vector.y), + detail, + distortion, + stack_valid(color_stack_offset), + &value, + &color); + break; + case 3: + noise_texture_3d( + vector, detail, distortion, stack_valid(color_stack_offset), &value, &color); + break; + case 4: + noise_texture_4d(make_float4(vector.x, vector.y, vector.z, w), + detail, + distortion, + stack_valid(color_stack_offset), + &value, + &color); + break; + default: + kernel_assert(0); + } - if (stack_valid(fac_offset)) { - stack_store_float(stack, fac_offset, f); + if (stack_valid(value_stack_offset)) { + stack_store_float(stack, value_stack_offset, value); } - if (stack_valid(color_offset)) { - float3 color = make_float3(f, - noise_turbulence(make_float3(p.y, p.x, p.z), detail, hard), - noise_turbulence(make_float3(p.y, p.z, p.x), detail, hard)); - stack_store_float3(stack, color_offset, color); + if (stack_valid(color_stack_offset)) { + stack_store_float3(stack, color_stack_offset, color); } } diff --git a/intern/cycles/kernel/svm/svm_texture.h b/intern/cycles/kernel/svm/svm_texture.h deleted file mode 100644 index 290aa85c831..00000000000 --- a/intern/cycles/kernel/svm/svm_texture.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2011-2013 Blender Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -CCL_NAMESPACE_BEGIN - -/* Turbulence */ - -ccl_device_noinline float noise_turbulence(float3 p, float octaves, int hard) -{ - float fscale = 1.0f; - float amp = 1.0f; - float sum = 0.0f; - int i, n; - - octaves = clamp(octaves, 0.0f, 16.0f); - n = float_to_int(octaves); - - for (i = 0; i <= n; i++) { - float t = noise(fscale * p); - - if (hard) - t = fabsf(2.0f * t - 1.0f); - - sum += t * amp; - amp *= 0.5f; - fscale *= 2.0f; - } - - float rmd = octaves - floorf(octaves); - - if (rmd != 0.0f) { - float t = noise(fscale * p); - - if (hard) - t = fabsf(2.0f * t - 1.0f); - - float sum2 = sum + t * amp; - - sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); - sum2 *= ((float)(1 << (n + 1)) / (float)((1 << (n + 2)) - 1)); - - return (1.0f - rmd) * sum + rmd * sum2; - } - else { - sum *= ((float)(1 << n) / (float)((1 << (n + 1)) - 1)); - return sum; - } -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index a3caa1ab68d..de7114566b3 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -140,6 +140,7 @@ typedef enum ShaderNodeType { NODE_IES, NODE_MAP_RANGE, NODE_CLAMP, + NODE_TEXTURE_MAPPING, NODE_TEX_WHITE_NOISE, } ShaderNodeType; @@ -299,6 +300,13 @@ typedef enum NodeVectorMathType { NODE_VECTOR_MATH_MAXIMUM, } NodeVectorMathType; +typedef enum NodeMappingType { + NODE_MAPPING_TYPE_POINT, + NODE_MAPPING_TYPE_TEXTURE, + NODE_MAPPING_TYPE_VECTOR, + NODE_MAPPING_TYPE_NORMAL +} NodeMappingType; + typedef enum NodeVectorTransformType { NODE_VECTOR_TRANSFORM_TYPE_VECTOR, NODE_VECTOR_TRANSFORM_TYPE_POINT, diff --git a/intern/cycles/kernel/svm/svm_wave.h b/intern/cycles/kernel/svm/svm_wave.h index baaa89ab0cb..402c1c87414 100644 --- a/intern/cycles/kernel/svm/svm_wave.h +++ b/intern/cycles/kernel/svm/svm_wave.h @@ -33,7 +33,7 @@ ccl_device_noinline_cpu float svm_wave(NodeWaveType type, n = len(p) * 20.0f; if (distortion != 0.0f) - n += distortion * noise_turbulence(p * dscale, detail, 0); + n += distortion * fractal_noise_3d(p * dscale, detail); if (profile == NODE_WAVE_PROFILE_SIN) { return 0.5f + 0.5f * sinf(n); diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp index 851d4b71df8..f3809ee8d80 100644 --- a/intern/cycles/render/constant_fold.cpp +++ b/intern/cycles/render/constant_fold.cpp @@ -429,4 +429,21 @@ void ConstantFolder::fold_vector_math(NodeVectorMathType type) const } } +void ConstantFolder::fold_mapping(NodeMappingType type) const +{ + ShaderInput *vector_in = node->input("Vector"); + ShaderInput *location_in = node->input("Location"); + ShaderInput *rotation_in = node->input("Rotation"); + ShaderInput *scale_in = node->input("Scale"); + + if (is_zero(scale_in)) { + make_zero(); + } + else if ((is_zero(location_in) || type == NODE_MAPPING_TYPE_VECTOR || + type == NODE_MAPPING_TYPE_NORMAL) && + is_zero(rotation_in) && is_one(scale_in)) { + try_bypass_or_make_constant(vector_in); + } +} + CCL_NAMESPACE_END diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h index 881636a9fe1..7f622488a88 100644 --- a/intern/cycles/render/constant_fold.h +++ b/intern/cycles/render/constant_fold.h @@ -66,6 +66,7 @@ class ConstantFolder { void fold_mix(NodeMix type, bool clamp) const; void fold_math(NodeMathType type) const; void fold_vector_math(NodeVectorMathType type) const; + void fold_mapping(NodeMappingType type) const; }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index bf8185d2b38..31dc986a4d1 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -25,6 +25,7 @@ #include "kernel/svm/svm_color_util.h" #include "kernel/svm/svm_ramp_util.h" #include "kernel/svm/svm_math_util.h" +#include "kernel/svm/svm_mapping_util.h" #include "render/osl.h" #include "render/constant_fold.h" @@ -149,7 +150,7 @@ bool TextureMapping::skip() void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_out) { - compiler.add_node(NODE_MAPPING, offset_in, offset_out); + compiler.add_node(NODE_TEXTURE_MAPPING, offset_in, offset_out); Transform tfm = compute_transform(); compiler.add_node(tfm.x); @@ -893,14 +894,22 @@ NODE_DEFINE(NoiseTextureNode) TEXTURE_MAPPING_DEFINE(NoiseTextureNode); + static NodeEnum dimensions_enum; + dimensions_enum.insert("1D", 1); + dimensions_enum.insert("2D", 2); + dimensions_enum.insert("3D", 3); + dimensions_enum.insert("4D", 4); + SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3); + + SOCKET_IN_POINT( + vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); + SOCKET_IN_FLOAT(w, "W", 0.0f); SOCKET_IN_FLOAT(scale, "Scale", 1.0f); SOCKET_IN_FLOAT(detail, "Detail", 2.0f); SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f); - SOCKET_IN_POINT( - vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED); - SOCKET_OUT_COLOR(color, "Color"); SOCKET_OUT_FLOAT(fac, "Fac"); + SOCKET_OUT_COLOR(color, "Color"); return type; } @@ -911,31 +920,40 @@ NoiseTextureNode::NoiseTextureNode() : TextureNode(node_type) void NoiseTextureNode::compile(SVMCompiler &compiler) { - ShaderInput *distortion_in = input("Distortion"); - ShaderInput *detail_in = input("Detail"); - ShaderInput *scale_in = input("Scale"); ShaderInput *vector_in = input("Vector"); - ShaderOutput *color_out = output("Color"); + ShaderInput *w_in = input("W"); + ShaderInput *scale_in = input("Scale"); + ShaderInput *detail_in = input("Detail"); + ShaderInput *distortion_in = input("Distortion"); ShaderOutput *fac_out = output("Fac"); + ShaderOutput *color_out = output("Color"); - int vector_offset = tex_mapping.compile_begin(compiler, vector_in); + int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in); + int w_stack_offset = compiler.stack_assign_if_linked(w_in); + int scale_stack_offset = compiler.stack_assign_if_linked(scale_in); + int detail_stack_offset = compiler.stack_assign_if_linked(detail_in); + int distortion_stack_offset = compiler.stack_assign_if_linked(distortion_in); + int fac_stack_offset = compiler.stack_assign_if_linked(fac_out); + int color_stack_offset = compiler.stack_assign_if_linked(color_out); - compiler.add_node(NODE_TEX_NOISE, - compiler.encode_uchar4(vector_offset, - compiler.stack_assign_if_linked(scale_in), - compiler.stack_assign_if_linked(detail_in), - compiler.stack_assign_if_linked(distortion_in)), - compiler.encode_uchar4(compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(fac_out))); - compiler.add_node(__float_as_int(scale), __float_as_int(detail), __float_as_int(distortion)); + compiler.add_node( + NODE_TEX_NOISE, + dimensions, + compiler.encode_uchar4( + vector_stack_offset, w_stack_offset, scale_stack_offset, detail_stack_offset), + compiler.encode_uchar4(distortion_stack_offset, fac_stack_offset, color_stack_offset)); + compiler.add_node(__float_as_int(w), + __float_as_int(scale), + __float_as_int(detail), + __float_as_int(distortion)); - tex_mapping.compile_end(compiler, vector_in, vector_offset); + tex_mapping.compile_end(compiler, vector_in, vector_stack_offset); } void NoiseTextureNode::compile(OSLCompiler &compiler) { tex_mapping.compile(compiler); - + compiler.parameter(this, "dimensions"); compiler.add(this, "node_noise_texture"); } @@ -1710,9 +1728,18 @@ NODE_DEFINE(MappingNode) { NodeType *type = NodeType::add("mapping", create, NodeType::SHADER); - TEXTURE_MAPPING_DEFINE(MappingNode); + static NodeEnum type_enum; + type_enum.insert("point", NODE_MAPPING_TYPE_POINT); + type_enum.insert("texture", NODE_MAPPING_TYPE_TEXTURE); + type_enum.insert("vector", NODE_MAPPING_TYPE_VECTOR); + type_enum.insert("normal", NODE_MAPPING_TYPE_NORMAL); + SOCKET_ENUM(type, "Type", type_enum, NODE_MAPPING_TYPE_POINT); SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_POINT(location, "Location", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_POINT(rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_POINT(scale, "Scale", make_float3(1.0f, 1.0f, 1.0f)); + SOCKET_OUT_POINT(vector, "Vector"); return type; @@ -1722,22 +1749,42 @@ MappingNode::MappingNode() : ShaderNode(node_type) { } +void MappingNode::constant_fold(const ConstantFolder &folder) +{ + if (folder.all_inputs_constant()) { + float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale); + folder.make_constant(result); + } + else { + folder.fold_mapping((NodeMappingType)type); + } +} + void MappingNode::compile(SVMCompiler &compiler) { ShaderInput *vector_in = input("Vector"); + ShaderInput *location_in = input("Location"); + ShaderInput *rotation_in = input("Rotation"); + ShaderInput *scale_in = input("Scale"); ShaderOutput *vector_out = output("Vector"); - tex_mapping.compile( - compiler, compiler.stack_assign(vector_in), compiler.stack_assign(vector_out)); + int vector_stack_offset = compiler.stack_assign(vector_in); + int location_stack_offset = compiler.stack_assign(location_in); + int rotation_stack_offset = compiler.stack_assign(rotation_in); + int scale_stack_offset = compiler.stack_assign(scale_in); + int result_stack_offset = compiler.stack_assign(vector_out); + + compiler.add_node( + NODE_MAPPING, + type, + compiler.encode_uchar4( + vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset), + result_stack_offset); } void MappingNode::compile(OSLCompiler &compiler) { - compiler.parameter("Matrix", tex_mapping.compute_transform()); - compiler.parameter_point("mapping_min", tex_mapping.min); - compiler.parameter_point("mapping_max", tex_mapping.max); - compiler.parameter("use_minmax", tex_mapping.use_minmax); - + compiler.parameter(this, "type"); compiler.add(this, "node_mapping"); } diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index fbed2ff0ef6..769687f1f19 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -206,7 +206,8 @@ class NoiseTextureNode : public TextureNode { public: SHADER_NODE_CLASS(NoiseTextureNode) - float scale, detail, distortion; + int dimensions; + float w, scale, detail, distortion; float3 vector; }; @@ -390,9 +391,10 @@ class MappingNode : public ShaderNode { { return NODE_GROUP_LEVEL_2; } + void constant_fold(const ConstantFolder &folder); - float3 vector; - TextureMapping tex_mapping; + float3 vector, location, rotation, scale; + NodeMappingType type; }; class RGBToBWNode : public ShaderNode { diff --git a/intern/cycles/util/util_hash.h b/intern/cycles/util/util_hash.h index 2b1f26de03d..53140e40fc9 100644 --- a/intern/cycles/util/util_hash.h +++ b/intern/cycles/util/util_hash.h @@ -213,6 +213,109 @@ ccl_device_inline float3 hash_float4_to_float3(float4 k) hash_float4_to_float(make_float4(k.w, k.z, k.y, k.x))); } +/* SSE Versions Of Jenkins Lookup3 Hash Functions */ + +#ifdef __KERNEL_SSE2__ +# define rot(x, k) (((x) << (k)) | (srl(x, 32 - (k)))) + +# define mix(a, b, c) \ + { \ + a -= c; \ + a ^= rot(c, 4); \ + c += b; \ + b -= a; \ + b ^= rot(a, 6); \ + a += c; \ + c -= b; \ + c ^= rot(b, 8); \ + b += a; \ + a -= c; \ + a ^= rot(c, 16); \ + c += b; \ + b -= a; \ + b ^= rot(a, 19); \ + a += c; \ + c -= b; \ + c ^= rot(b, 4); \ + b += a; \ + } + +# define final(a, b, c) \ + { \ + c ^= b; \ + c -= rot(b, 14); \ + a ^= c; \ + a -= rot(c, 11); \ + b ^= a; \ + b -= rot(a, 25); \ + c ^= b; \ + c -= rot(b, 16); \ + a ^= c; \ + a -= rot(c, 4); \ + b ^= a; \ + b -= rot(a, 14); \ + c ^= b; \ + c -= rot(b, 24); \ + } + +ccl_device_inline ssei hash_ssei(ssei kx) +{ + ssei a, b, c; + a = b = c = ssei(0xdeadbeef + (1 << 2) + 13); + + a += kx; + final(a, b, c); + + return c; +} + +ccl_device_inline ssei hash_ssei2(ssei kx, ssei ky) +{ + ssei a, b, c; + a = b = c = ssei(0xdeadbeef + (2 << 2) + 13); + + b += ky; + a += kx; + final(a, b, c); + + return c; +} + +ccl_device_inline ssei hash_ssei3(ssei kx, ssei ky, ssei kz) +{ + ssei a, b, c; + a = b = c = ssei(0xdeadbeef + (3 << 2) + 13); + + c += kz; + b += ky; + a += kx; + final(a, b, c); + + return c; +} + +ccl_device_inline ssei hash_ssei4(ssei kx, ssei ky, ssei kz, ssei kw) +{ + ssei a, b, c; + a = b = c = ssei(0xdeadbeef + (4 << 2) + 13); + + a += kx; + b += ky; + c += kz; + mix(a, b, c); + + a += kw; + final(a, b, c); + + return c; +} + +# undef rot +# undef final +# undef mix + +#endif + #ifndef __KERNEL_GPU__ static inline uint hash_string(const char *str) { diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index ebddd56bd40..17bb766445d 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -318,6 +318,12 @@ ccl_device_inline int quick_floor_to_int(float x) return float_to_int(x) - ((x < 0) ? 1 : 0); } +ccl_device_inline float floorfrac(float x, int *i) +{ + *i = quick_floor_to_int(x); + return x - *i; +} + ccl_device_inline int ceil_to_int(float f) { return float_to_int(ceilf(f)); diff --git a/intern/cycles/util/util_ssef.h b/intern/cycles/util/util_ssef.h index e6610dbb197..fa525daf37c 100644 --- a/intern/cycles/util/util_ssef.h +++ b/intern/cycles/util/util_ssef.h @@ -523,13 +523,29 @@ __forceinline ssei truncatei(const ssef &a) return _mm_cvttps_epi32(a.m128); } +/* This is about 25% faster than straightforward floor to integer conversion + * due to better pipelining. + * + * Unsaturated add 0xffffffff (a < 0) is the same as subtract -1. + */ __forceinline ssei floori(const ssef &a) { -# if defined(__KERNEL_SSE41__) - return ssei(floor(a)); -# else - return ssei(a - ssef(0.5f)); -# endif + return truncatei(a) + cast((a < 0.0f).m128); +} + +__forceinline ssef floorfrac(const ssef &x, ssei *i) +{ + *i = floori(x); + return x - ssef(*i); +} + +//////////////////////////////////////////////////////////////////////////////// +/// Common Functions +//////////////////////////////////////////////////////////////////////////////// + +__forceinline ssef mix(const ssef &a, const ssef &b, const ssef &t) +{ + return madd(t, b, (ssef(1.0f) - t) * a); } //////////////////////////////////////////////////////////////////////////////// diff --git a/intern/cycles/util/util_ssei.h b/intern/cycles/util/util_ssei.h index 86429260a0e..e2bf81310cc 100644 --- a/intern/cycles/util/util_ssei.h +++ b/intern/cycles/util/util_ssei.h @@ -310,6 +310,15 @@ __forceinline ssei &operator|=(ssei &a, const int32_t &b) return a = a | b; } +__forceinline ssei &operator^=(ssei &a, const ssei &b) +{ + return a = a ^ b; +} +__forceinline ssei &operator^=(ssei &a, const int32_t &b) +{ + return a = a ^ b; +} + __forceinline ssei &operator<<=(ssei &a, const int32_t &b) { return a = a << b; diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index cfe71d696ed..407654245cb 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -148,6 +148,32 @@ ccl_device_inline Transform make_transform(float a, return t; } +ccl_device_inline Transform euler_to_transform(const float3 euler) +{ + float cx = cosf(euler.x); + float cy = cosf(euler.y); + float cz = cosf(euler.z); + float sx = sinf(euler.x); + float sy = sinf(euler.y); + float sz = sinf(euler.z); + + Transform t; + t.x.x = cy * cz; + t.y.x = cy * sz; + t.z.x = -sy; + + t.x.y = sy * sx * cz - cx * sz; + t.y.y = sy * sx * sz + cx * cz; + t.z.y = cy * sx; + + t.x.z = sy * cx * cz + sx * sz; + t.y.z = sy * cx * sz - sx * cz; + t.z.z = cy * cx; + + t.x.w = t.y.w = t.z.w = 0.0f; + return t; +} + /* Constructs a coordinate frame from a normalized normal. */ ccl_device_inline Transform make_transform_frame(float3 N) { diff --git a/intern/memutil/MEM_RefCounted.h b/intern/memutil/MEM_RefCounted.h index 28b24d04586..42e595aadf4 100644 --- a/intern/memutil/MEM_RefCounted.h +++ b/intern/memutil/MEM_RefCounted.h @@ -34,8 +34,8 @@ * The default destructor of this object has been made protected on purpose. * This disables the creation of shared objects on the stack. * - * @author Maarten Gribnau - * @date March 31, 2001 + * \author Maarten Gribnau + * \date March 31, 2001 */ class MEM_RefCounted { @@ -49,20 +49,20 @@ class MEM_RefCounted { /** * Returns the reference count of this object. - * @return the reference count. + * \return the reference count. */ inline virtual int getRef() const; /** * Increases the reference count of this object. - * @return the new reference count. + * \return the new reference count. */ inline virtual int incRef(); /** * Decreases the reference count of this object. * If the reference count reaches zero, the object self-destructs. - * @return the new reference count. + * \return the new reference count. */ inline virtual int decRef(); diff --git a/intern/utfconv/utfconv.h b/intern/utfconv/utfconv.h index befaeae63de..46c07500bf7 100644 --- a/intern/utfconv/utfconv.h +++ b/intern/utfconv/utfconv.h @@ -31,15 +31,15 @@ extern "C" { /** * Counts how many bytes is requered for for future utf-8 string using utf-16 - * @param string-16 pointer to working utf-16 string - * @return How many bytes must be allocated includeng NULL. + * \param string16: pointer to working utf-16 string + * \return How many bytes must be allocated includeng NULL. */ size_t count_utf_8_from_16(const wchar_t *string16); /** * Counts how many wchar_t (two byte) is requered for for future utf-16 string using utf-8 - * @param string-8 pointer to working utf-8 string - * @return How many bytes must be allocated includeng NULL. + * \param string8: pointer to working utf-8 string + * \return How many bytes must be allocated includeng NULL. */ size_t count_utf_16_from_8(const char *string8); @@ -54,36 +54,36 @@ size_t count_utf_16_from_8(const char *string8); /** * Converts utf-16 string to allocated utf-8 string - * @param in16 utf-16 string to convert - * @param out8 utf-8 string to string the conversion - * @param size8 the allocated size in bytes of out8 - * @return Returns any errors occured during conversion. See the block above, + * \param in16: utf-16 string to convert + * \param out8: utf-8 string to string the conversion + * \param size8: the allocated size in bytes of out8 + * \return Returns any errors occured during conversion. See the block above, */ int conv_utf_16_to_8(const wchar_t *in16, char *out8, size_t size8); /** * Converts utf-8 string to allocated utf-16 string - * @param in8 utf-8 string to convert - * @param out16 utf-16 string to string the conversion - * @param size16 the allocated size in wchar_t (two byte) of out16 - * @return Returns any errors occured during conversion. See the block above, + * \param in8: utf-8 string to convert + * \param out16: utf-16 string to string the conversion + * \param size16: the allocated size in wchar_t (two byte) of out16 + * \return Returns any errors occured during conversion. See the block above, */ int conv_utf_8_to_16(const char *in8, wchar_t *out16, size_t size16); /** * Allocates and converts the utf-8 string from utf-16 - * @param in16 utf-16 string to convert - * @param add any additional size which will be allocated for new utf-8 string in bytes - * @return New allocated and converted utf-8 string or NULL if in16 is 0. + * \param in16: utf-16 string to convert + * \param add: any additional size which will be allocated for new utf-8 string in bytes + * \return New allocated and converted utf-8 string or NULL if in16 is 0. */ char *alloc_utf_8_from_16(const wchar_t *in16, size_t add); /** * Allocates and converts the utf-16 string from utf-8 - * @param in8 utf-8 string to convert - * @param add any additional size which will be allocated for new utf-16 string + * \param in8: utf-8 string to convert + * \param add: any additional size which will be allocated for new utf-16 string * in wchar_t (two bytes) - * @return New allocated and converted utf-16 string or NULL if in8 is 0. + * \return New allocated and converted utf-16 string or NULL if in8 is 0. */ wchar_t *alloc_utf16_from_8(const char *in8, size_t add); |