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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/cycles/blender/blender_curves.cpp2
-rw-r--r--intern/cycles/blender/blender_mesh.cpp20
-rw-r--r--intern/cycles/blender/blender_object.cpp5
-rw-r--r--intern/cycles/blender/blender_session.cpp8
-rw-r--r--intern/cycles/blender/blender_shader.cpp67
-rw-r--r--intern/cycles/blender/blender_sync.cpp6
-rw-r--r--intern/cycles/kernel/CMakeLists.txt5
-rw-r--r--intern/cycles/kernel/geom/geom_object.h11
-rw-r--r--intern/cycles/kernel/geom/geom_patch.h14
-rw-r--r--intern/cycles/kernel/geom/geom_primitive.h21
-rw-r--r--intern/cycles/kernel/geom/geom_subd_triangle.h124
-rw-r--r--intern/cycles/kernel/geom/geom_triangle.h32
-rw-r--r--intern/cycles/kernel/kernel_random.h2
-rw-r--r--intern/cycles/kernel/kernel_types.h3
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp72
-rw-r--r--intern/cycles/kernel/osl/osl_services.h1
-rw-r--r--intern/cycles/kernel/shaders/CMakeLists.txt6
-rw-r--r--intern/cycles/kernel/shaders/node_brick_texture.osl1
-rw-r--r--intern/cycles/kernel/shaders/node_checker_texture.osl1
-rw-r--r--intern/cycles/kernel/shaders/node_clamp.osl23
-rw-r--r--intern/cycles/kernel/shaders/node_gradient_texture.osl1
-rw-r--r--intern/cycles/kernel/shaders/node_ies_light.osl1
-rw-r--r--intern/cycles/kernel/shaders/node_magic_texture.osl1
-rw-r--r--intern/cycles/kernel/shaders/node_map_range.osl28
-rw-r--r--intern/cycles/kernel/shaders/node_mapping.osl58
-rw-r--r--intern/cycles/kernel/shaders/node_math.osl121
-rw-r--r--intern/cycles/kernel/shaders/node_musgrave_texture.osl710
-rw-r--r--intern/cycles/kernel/shaders/node_noise_texture.osl127
-rw-r--r--intern/cycles/kernel/shaders/node_object_info.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_texture.h251
-rw-r--r--intern/cycles/kernel/shaders/node_vector_math.osl97
-rw-r--r--intern/cycles/kernel/shaders/node_vertex_color.osl40
-rw-r--r--intern/cycles/kernel/shaders/node_voronoi_texture.osl1093
-rw-r--r--intern/cycles/kernel/shaders/node_wave_texture.osl2
-rw-r--r--intern/cycles/kernel/shaders/node_white_noise_texture.osl39
-rw-r--r--intern/cycles/kernel/shaders/vector2.h291
-rw-r--r--intern/cycles/kernel/shaders/vector4.h327
-rw-r--r--intern/cycles/kernel/svm/svm.h34
-rw-r--r--intern/cycles/kernel/svm/svm_attribute.h29
-rw-r--r--intern/cycles/kernel/svm/svm_clamp.h38
-rw-r--r--intern/cycles/kernel/svm/svm_geometry.h6
-rw-r--r--intern/cycles/kernel/svm/svm_map_range.h47
-rw-r--r--intern/cycles/kernel/svm/svm_mapping.h23
-rw-r--r--intern/cycles/kernel/svm/svm_mapping_util.h46
-rw-r--r--intern/cycles/kernel/svm/svm_math.h38
-rw-r--r--intern/cycles/kernel/svm/svm_math_util.h207
-rw-r--r--intern/cycles/kernel/svm/svm_musgrave.h748
-rw-r--r--intern/cycles/kernel/svm/svm_noise.h703
-rw-r--r--intern/cycles/kernel/svm/svm_noisetex.h171
-rw-r--r--intern/cycles/kernel/svm/svm_texture.h105
-rw-r--r--intern/cycles/kernel/svm/svm_types.h63
-rw-r--r--intern/cycles/kernel/svm/svm_vertex_color.h92
-rw-r--r--intern/cycles/kernel/svm/svm_voronoi.h1158
-rw-r--r--intern/cycles/kernel/svm/svm_wave.h2
-rw-r--r--intern/cycles/kernel/svm/svm_white_noise.h52
-rw-r--r--intern/cycles/render/attribute.cpp3
-rw-r--r--intern/cycles/render/bake.cpp2
-rw-r--r--intern/cycles/render/constant_fold.cpp114
-rw-r--r--intern/cycles/render/constant_fold.h5
-rw-r--r--intern/cycles/render/graph.cpp10
-rw-r--r--intern/cycles/render/integrator.cpp2
-rw-r--r--intern/cycles/render/mesh.cpp10
-rw-r--r--intern/cycles/render/nodes.cpp629
-rw-r--r--intern/cycles/render/nodes.h95
-rw-r--r--intern/cycles/render/object.cpp5
-rw-r--r--intern/cycles/render/object.h1
-rw-r--r--intern/cycles/subd/subd_dice.cpp4
-rw-r--r--intern/cycles/subd/subd_split.cpp8
-rw-r--r--intern/cycles/test/render_graph_finalize_test.cpp82
-rw-r--r--intern/cycles/util/util_color.h18
-rw-r--r--intern/cycles/util/util_hash.h299
-rw-r--r--intern/cycles/util/util_math.h6
-rw-r--r--intern/cycles/util/util_math_float2.h20
-rw-r--r--intern/cycles/util/util_math_float3.h63
-rw-r--r--intern/cycles/util/util_math_float4.h45
-rw-r--r--intern/cycles/util/util_param.h5
-rw-r--r--intern/cycles/util/util_ssef.h24
-rw-r--r--intern/cycles/util/util_ssei.h9
-rw-r--r--intern/cycles/util/util_transform.h29
-rw-r--r--release/scripts/startup/nodeitems_builtins.py5
-rw-r--r--source/blender/blenkernel/BKE_node.h8
-rw-r--r--source/blender/blenkernel/intern/node.c20
-rw-r--r--source/blender/blenlib/BLI_math_vector.h2
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c14
-rw-r--r--source/blender/blenloader/intern/versioning_cycles.c596
-rw-r--r--source/blender/compositor/nodes/COM_MathNode.cpp36
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c13
-rw-r--r--source/blender/draw/intern/draw_manager.c1
-rw-r--r--source/blender/draw/intern/draw_manager.h3
-rw-r--r--source/blender/draw/intern/draw_manager_data.c8
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c4
-rw-r--r--source/blender/editors/space_node/drawnode.c83
-rw-r--r--source/blender/gpu/GPU_material.h2
-rw-r--r--source/blender/gpu/GPU_shader_interface.h7
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c14
-rw-r--r--source/blender/gpu/intern/gpu_shader_interface.c1
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl2946
-rw-r--r--source/blender/makesdna/DNA_node_types.h109
-rw-r--r--source/blender/makesrna/RNA_enum_types.h1
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c278
-rw-r--r--source/blender/makesrna/intern/rna_object.c2
-rw-r--r--source/blender/makesrna/intern/rna_texture.c14
-rw-r--r--source/blender/nodes/CMakeLists.txt5
-rw-r--r--source/blender/nodes/NOD_shader.h5
-rw-r--r--source/blender/nodes/NOD_static_types.h7
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c2
-rw-r--r--source/blender/nodes/shader/node_shader_util.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c12
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_clamp.c57
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_map_range.c59
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_mapping.c105
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.c381
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_object_info.c18
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c84
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_noise.c39
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c171
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c77
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectMath.c160
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vertex_color.c58
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_volume_info.c56
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_math.c36
122 files changed, 11602 insertions, 2564 deletions
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp
index 29a1408d85d..0075ce533dd 100644
--- a/intern/cycles/blender/blender_curves.cpp
+++ b/intern/cycles/blender/blender_curves.cpp
@@ -656,7 +656,7 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa
}
if (attr_random != NULL) {
- attr_random->add(hash_int_01(num_curves));
+ attr_random->add(hash_uint_to_float(num_curves));
}
mesh->add_curve(num_keys, CData->psys_shader[sys]);
diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp
index c672bc9f3e2..ece8d02bee9 100644
--- a/intern/cycles/blender/blender_mesh.cpp
+++ b/intern/cycles/blender/blender_mesh.cpp
@@ -335,7 +335,7 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
continue;
Attribute *attr = mesh->subd_attributes.add(
- ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
+ ustring(l->name().c_str()), TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
BL::Mesh::polygons_iterator p;
uchar4 *cdata = attr->data_uchar4();
@@ -343,9 +343,9 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
for (b_mesh.polygons.begin(p); p != b_mesh.polygons.end(); ++p) {
int n = p->loop_total();
for (int i = 0; i < n; i++) {
- float3 color = get_float3(l->data[p->loop_start() + i].color());
+ float4 color = get_float4(l->data[p->loop_start() + i].color());
/* Compress/encode vertex color using the sRGB curve. */
- *(cdata++) = color_float_to_byte(color_srgb_to_linear_v3(color));
+ *(cdata++) = color_float4_to_uchar4(color_srgb_to_linear_v4(color));
}
}
}
@@ -357,21 +357,21 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
continue;
Attribute *attr = mesh->attributes.add(
- ustring(l->name().c_str()), TypeDesc::TypeColor, ATTR_ELEMENT_CORNER_BYTE);
+ ustring(l->name().c_str()), TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
BL::Mesh::loop_triangles_iterator t;
uchar4 *cdata = attr->data_uchar4();
for (b_mesh.loop_triangles.begin(t); t != b_mesh.loop_triangles.end(); ++t) {
int3 li = get_int3(t->loops());
- float3 c1 = get_float3(l->data[li[0]].color());
- float3 c2 = get_float3(l->data[li[1]].color());
- float3 c3 = get_float3(l->data[li[2]].color());
+ float4 c1 = get_float4(l->data[li[0]].color());
+ float4 c2 = get_float4(l->data[li[1]].color());
+ float4 c3 = get_float4(l->data[li[2]].color());
/* Compress/encode vertex color using the sRGB curve. */
- cdata[0] = color_float_to_byte(color_srgb_to_linear_v3(c1));
- cdata[1] = color_float_to_byte(color_srgb_to_linear_v3(c2));
- cdata[2] = color_float_to_byte(color_srgb_to_linear_v3(c3));
+ cdata[0] = color_float4_to_uchar4(color_srgb_to_linear_v4(c1));
+ cdata[1] = color_float4_to_uchar4(color_srgb_to_linear_v4(c2));
+ cdata[2] = color_float4_to_uchar4(color_srgb_to_linear_v4(c3));
cdata += 3;
}
}
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 7ccf8226e5b..b670922ac88 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -217,7 +217,7 @@ void BlenderSync::sync_light(BL::Object &b_parent,
light->random_id = random_id;
}
else {
- light->random_id = hash_int_2d(hash_string(b_ob.name().c_str()), 0);
+ light->random_id = hash_uint2(hash_string(b_ob.name().c_str()), 0);
}
if (light->type == LIGHT_AREA)
@@ -444,6 +444,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
if (object_updated || (object->mesh && object->mesh->need_update) || tfm != object->tfm) {
object->name = b_ob.name().c_str();
object->pass_id = b_ob.pass_index();
+ object->color = get_float3(b_ob.color());
object->tfm = tfm;
object->motion.clear();
@@ -490,7 +491,7 @@ Object *BlenderSync::sync_object(BL::Depsgraph &b_depsgraph,
else {
object->dupli_generated = make_float3(0.0f, 0.0f, 0.0f);
object->dupli_uv = make_float2(0.0f, 0.0f);
- object->random_id = hash_int_2d(hash_string(object->name.c_str()), 0);
+ object->random_id = hash_uint2(hash_string(object->name.c_str()), 0);
}
object->tag_update(scene);
diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp
index d38a97dc4ea..67b227ccb99 100644
--- a/intern/cycles/blender/blender_session.cpp
+++ b/intern/cycles/blender/blender_session.cpp
@@ -539,8 +539,8 @@ void BlenderSession::render(BL::Depsgraph &b_depsgraph_)
/* Make sure all views have different noise patterns. - hardcoded value just to make it random
*/
if (view_index != 0) {
- scene->integrator->seed += hash_int_2d(scene->integrator->seed,
- hash_int(view_index * 0xdeadbeef));
+ scene->integrator->seed += hash_uint2(scene->integrator->seed,
+ hash_uint(view_index * 0xdeadbeef));
scene->integrator->tag_update(scene);
}
@@ -1481,8 +1481,8 @@ void BlenderSession::update_resumable_tile_manager(int num_samples)
/* Round after doing the multiplications with num_chunks and num_samples_per_chunk
* to allow for many small chunks. */
- int rounded_range_start_sample = (int)floor(range_start_sample + 0.5f);
- int rounded_range_num_samples = max((int)floor(range_num_samples + 0.5f), 1);
+ int rounded_range_start_sample = (int)floorf(range_start_sample + 0.5f);
+ int rounded_range_num_samples = max((int)floorf(range_num_samples + 0.5f), 1);
/* Make sure we don't overshoot. */
if (rounded_range_start_sample + rounded_range_num_samples > num_samples) {
diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp
index f952b3025f0..c98d7122144 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,
@@ -315,17 +297,22 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeRGBToBW)) {
node = new RGBToBWNode();
}
+ else if (b_node.is_a(&RNA_ShaderNodeMapRange)) {
+ node = new MapRangeNode();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeClamp)) {
+ node = new ClampNode();
+ }
else if (b_node.is_a(&RNA_ShaderNodeMath)) {
BL::ShaderNodeMath b_math_node(b_node);
MathNode *math = new MathNode();
- math->type = (NodeMath)b_math_node.operation();
- math->use_clamp = b_math_node.use_clamp();
+ math->type = (NodeMathType)b_math_node.operation();
node = math;
}
else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) {
BL::ShaderNodeVectorMath b_vector_math_node(b_node);
VectorMathNode *vmath = new VectorMathNode();
- vmath->type = (NodeVectorMath)b_vector_math_node.operation();
+ vmath->type = (NodeVectorMathType)b_vector_math_node.operation();
node = vmath;
}
else if (b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
@@ -348,9 +335,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)) {
@@ -598,6 +583,15 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeHairInfo)) {
node = new HairInfoNode();
}
+ else if (b_node.is_a(&RNA_ShaderNodeVolumeInfo)) {
+ node = new VolumeInfoNode();
+ }
+ else if (b_node.is_a(&RNA_ShaderNodeVertexColor)) {
+ BL::ShaderNodeVertexColor b_vertex_color_node(b_node);
+ VertexColorNode *vertex_color = new VertexColorNode();
+ vertex_color->layer_name = b_vertex_color_node.layer_name();
+ node = vertex_color;
+ }
else if (b_node.is_a(&RNA_ShaderNodeBump)) {
BL::ShaderNodeBump b_bump_node(b_node);
BumpNode *bump = new BumpNode();
@@ -741,9 +735,9 @@ static ShaderNode *add_node(Scene *scene,
else if (b_node.is_a(&RNA_ShaderNodeTexVoronoi)) {
BL::ShaderNodeTexVoronoi b_voronoi_node(b_node);
VoronoiTextureNode *voronoi = new VoronoiTextureNode();
- voronoi->coloring = (NodeVoronoiColoring)b_voronoi_node.coloring();
- voronoi->metric = (NodeVoronoiDistanceMetric)b_voronoi_node.distance();
+ voronoi->dimensions = b_voronoi_node.dimensions();
voronoi->feature = (NodeVoronoiFeature)b_voronoi_node.feature();
+ voronoi->metric = (NodeVoronoiDistanceMetric)b_voronoi_node.distance();
BL::TexMapping b_texture_mapping(b_voronoi_node.texture_mapping());
get_tex_mapping(&voronoi->tex_mapping, b_texture_mapping);
node = voronoi;
@@ -786,6 +780,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;
@@ -794,6 +789,7 @@ static ShaderNode *add_node(Scene *scene,
BL::ShaderNodeTexMusgrave b_musgrave_node(b_node);
MusgraveTextureNode *musgrave = new MusgraveTextureNode();
musgrave->type = (NodeMusgraveType)b_musgrave_node.musgrave_type();
+ musgrave->dimensions = b_musgrave_node.dimensions();
BL::TexMapping b_texture_mapping(b_musgrave_node.texture_mapping());
get_tex_mapping(&musgrave->tex_mapping, b_texture_mapping);
node = musgrave;
@@ -835,6 +831,12 @@ static ShaderNode *add_node(Scene *scene,
}
node = ies;
}
+ else if (b_node.is_a(&RNA_ShaderNodeTexWhiteNoise)) {
+ BL::ShaderNodeTexWhiteNoise b_tex_white_noise_node(b_node);
+ WhiteNoiseTextureNode *whiteNoise = new WhiteNoiseTextureNode();
+ whiteNoise->dimensions = b_tex_white_noise_node.dimensions();
+ node = whiteNoise;
+ }
else if (b_node.is_a(&RNA_ShaderNodeNormalMap)) {
BL::ShaderNodeNormalMap b_normal_map_node(b_node);
NormalMapNode *nmap = new NormalMapNode();
@@ -1142,8 +1144,7 @@ static void add_nodes(Scene *scene,
for (b_node->inputs.begin(b_input); b_input != b_node->inputs.end(); ++b_input) {
ShaderInput *input = node_find_input_by_name(node, *b_node, *b_input);
if (!input) {
- /* XXX should not happen, report error? */
- continue;
+ assert(false);
}
input_map[b_input->ptr.data] = input;
@@ -1152,8 +1153,7 @@ static void add_nodes(Scene *scene,
for (b_node->outputs.begin(b_output); b_output != b_node->outputs.end(); ++b_output) {
ShaderOutput *output = node_find_output_by_name(node, *b_node, *b_output);
if (!output) {
- /* XXX should not happen, report error? */
- continue;
+ assert(false);
}
output_map[b_output->ptr.data] = output;
}
@@ -1165,8 +1165,11 @@ static void add_nodes(Scene *scene,
BL::NodeTree::links_iterator b_link;
for (b_ntree.links.begin(b_link); b_link != b_ntree.links.end(); ++b_link) {
- /* Ignore invalid links to avoid unwanted cycles created in graph. */
- if (!b_link->is_valid()) {
+ /* Ignore invalid links to avoid unwanted cycles created in graph.
+ * Also ignore links with unavailable sockets.
+ */
+ if (!(b_link->is_valid() && b_link->from_socket().enabled() &&
+ b_link->to_socket().enabled())) {
continue;
}
/* get blender link data */
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index bac571b02ce..16a44a0ffa3 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -255,13 +255,13 @@ void BlenderSync::sync_integrator()
integrator->seed = get_int(cscene, "seed");
if (get_boolean(cscene, "use_animated_seed")) {
- integrator->seed = hash_int_2d(b_scene.frame_current(), get_int(cscene, "seed"));
+ integrator->seed = hash_uint2(b_scene.frame_current(), get_int(cscene, "seed"));
if (b_scene.frame_subframe() != 0.0f) {
/* TODO(sergey): Ideally should be some sort of hash_merge,
* but this is good enough for now.
*/
- integrator->seed += hash_int_2d((int)(b_scene.frame_subframe() * (float)INT_MAX),
- get_int(cscene, "seed"));
+ integrator->seed += hash_uint2((uint)(b_scene.frame_subframe() * (float)INT_MAX),
+ get_int(cscene, "seed"));
}
}
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index cd284c06259..8daa845f830 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -198,7 +198,10 @@ set(SRC_SVM_HEADERS
svm/svm_invert.h
svm/svm_light_path.h
svm/svm_magic.h
+ svm/svm_map_range.h
+ svm/svm_clamp.h
svm/svm_mapping.h
+ svm/svm_mapping_util.h
svm/svm_math.h
svm/svm_math_util.h
svm/svm_mix.h
@@ -219,6 +222,8 @@ set(SRC_SVM_HEADERS
svm/svm_voronoi.h
svm/svm_voxel.h
svm/svm_wave.h
+ svm/svm_white_noise.h
+ svm/svm_vertex_color.h
)
set(SRC_GEOM_HEADERS
diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h
index f410e6e27e2..af4e6fbd89b 100644
--- a/intern/cycles/kernel/geom/geom_object.h
+++ b/intern/cycles/kernel/geom/geom_object.h
@@ -227,6 +227,17 @@ ccl_device_inline float object_surface_area(KernelGlobals *kg, int object)
return kernel_tex_fetch(__objects, object).surface_area;
}
+/* Color of the object */
+
+ccl_device_inline float3 object_color(KernelGlobals *kg, int object)
+{
+ if (object == OBJECT_NONE)
+ return make_float3(0.0f, 0.0f, 0.0f);
+
+ const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
+ return make_float3(kobject->color[0], kobject->color[1], kobject->color[2]);
+}
+
/* Pass ID number of object */
ccl_device_inline float object_pass_id(KernelGlobals *kg, int object)
diff --git a/intern/cycles/kernel/geom/geom_patch.h b/intern/cycles/kernel/geom/geom_patch.h
index df19199f68e..8b4b91b96c8 100644
--- a/intern/cycles/kernel/geom/geom_patch.h
+++ b/intern/cycles/kernel/geom/geom_patch.h
@@ -380,15 +380,15 @@ ccl_device float3 patch_eval_float3(KernelGlobals *kg,
return val;
}
-ccl_device float3 patch_eval_uchar4(KernelGlobals *kg,
+ccl_device float4 patch_eval_uchar4(KernelGlobals *kg,
const ShaderData *sd,
int offset,
int patch,
float u,
float v,
int channel,
- float3 *du,
- float3 *dv)
+ float4 *du,
+ float4 *dv)
{
int indices[PATCH_MAX_CONTROL_VERTS];
float weights[PATCH_MAX_CONTROL_VERTS];
@@ -398,14 +398,14 @@ ccl_device float3 patch_eval_uchar4(KernelGlobals *kg,
int num_control = patch_eval_control_verts(
kg, sd->object, patch, u, v, channel, indices, weights, weights_du, weights_dv);
- float3 val = make_float3(0.0f, 0.0f, 0.0f);
+ float4 val = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
if (du)
- *du = make_float3(0.0f, 0.0f, 0.0f);
+ *du = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
if (dv)
- *dv = make_float3(0.0f, 0.0f, 0.0f);
+ *dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
for (int i = 0; i < num_control; i++) {
- float3 v = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, offset + indices[i]));
+ float4 v = color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, offset + indices[i]));
val += v * weights[i];
if (du)
diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h
index 7f2b52a24c4..9a91da79f58 100644
--- a/intern/cycles/kernel/geom/geom_primitive.h
+++ b/intern/cycles/kernel/geom/geom_primitive.h
@@ -162,6 +162,27 @@ ccl_device_inline float3 primitive_attribute_float3(KernelGlobals *kg,
}
}
+ccl_device_inline float4 primitive_attribute_float4(KernelGlobals *kg,
+ const ShaderData *sd,
+ const AttributeDescriptor desc,
+ float4 *dx,
+ float4 *dy)
+{
+ if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
+ if (subd_triangle_patch(kg, sd) == ~0)
+ return triangle_attribute_float4(kg, sd, desc, dx, dy);
+ else
+ return subd_triangle_attribute_float4(kg, sd, desc, dx, dy);
+ }
+ else {
+ if (dx)
+ *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+}
+
ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals *kg,
const ShaderData *sd,
const AttributeDescriptor desc,
diff --git a/intern/cycles/kernel/geom/geom_subd_triangle.h b/intern/cycles/kernel/geom/geom_subd_triangle.h
index 8d5b3c12833..81bac6e6ee1 100644
--- a/intern/cycles/kernel/geom/geom_subd_triangle.h
+++ b/intern/cycles/kernel/geom/geom_subd_triangle.h
@@ -382,13 +382,7 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals *kg,
float2 p = dpdu * sd->u + dpdv * sd->v + uv[2];
float3 a, dads, dadt;
-
- if (desc.element == ATTR_ELEMENT_CORNER_BYTE) {
- a = patch_eval_uchar4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
- }
- else {
- a = patch_eval_float3(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
- }
+ a = patch_eval_float3(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
# ifdef __RAY_DIFFERENTIALS__
if (dx || dy) {
@@ -460,7 +454,7 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals *kg,
return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
}
- else if (desc.element == ATTR_ELEMENT_CORNER || desc.element == ATTR_ELEMENT_CORNER_BYTE) {
+ else if (desc.element == ATTR_ELEMENT_CORNER) {
float2 uv[3];
subd_triangle_patch_uv(kg, sd, uv);
@@ -469,18 +463,10 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals *kg,
float3 f0, f1, f2, f3;
- if (desc.element == ATTR_ELEMENT_CORNER) {
- f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset));
- f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset));
- f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset));
- f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset));
- }
- else {
- f0 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[0] + desc.offset));
- f1 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[1] + desc.offset));
- f2 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[2] + desc.offset));
- f3 = color_byte_to_float(kernel_tex_fetch(__attributes_uchar4, corners[3] + desc.offset));
- }
+ f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset));
+ f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset));
+ f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset));
+ f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset));
if (subd_triangle_patch_num_corners(kg, patch) != 4) {
f1 = (f1 + f0) * 0.5f;
@@ -510,4 +496,102 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals *kg,
}
}
+ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals *kg,
+ const ShaderData *sd,
+ const AttributeDescriptor desc,
+ float4 *dx,
+ float4 *dy)
+{
+ int patch = subd_triangle_patch(kg, sd);
+
+#ifdef __PATCH_EVAL__
+ if (desc.flags & ATTR_SUBDIVIDED) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ float2 dpdu = uv[0] - uv[2];
+ float2 dpdv = uv[1] - uv[2];
+
+ /* p is [s, t] */
+ float2 p = dpdu * sd->u + dpdv * sd->v + uv[2];
+
+ float4 dads, dadt;
+
+ float4 a = patch_eval_uchar4(kg, sd, desc.offset, patch, p.x, p.y, 0, &dads, &dadt);
+
+# ifdef __RAY_DIFFERENTIALS__
+ if (dx || dy) {
+ float dsdu = dpdu.x;
+ float dtdu = dpdu.y;
+ float dsdv = dpdv.x;
+ float dtdv = dpdv.y;
+
+ if (dx) {
+ float dudx = sd->du.dx;
+ float dvdx = sd->dv.dx;
+
+ float dsdx = dsdu * dudx + dsdv * dvdx;
+ float dtdx = dtdu * dudx + dtdv * dvdx;
+
+ *dx = dads * dsdx + dadt * dtdx;
+ }
+ if (dy) {
+ float dudy = sd->du.dy;
+ float dvdy = sd->dv.dy;
+
+ float dsdy = dsdu * dudy + dsdv * dvdy;
+ float dtdy = dtdu * dudy + dtdv * dvdy;
+
+ *dy = dads * dsdy + dadt * dtdy;
+ }
+ }
+# endif
+ return a;
+ }
+ else
+#endif /* __PATCH_EVAL__ */
+ if (desc.element == ATTR_ELEMENT_CORNER_BYTE) {
+ float2 uv[3];
+ subd_triangle_patch_uv(kg, sd, uv);
+
+ int corners[4];
+ subd_triangle_patch_corners(kg, patch, corners);
+
+ float4 f0 = color_uchar4_to_float4(
+ kernel_tex_fetch(__attributes_uchar4, corners[0] + desc.offset));
+ float4 f1 = color_uchar4_to_float4(
+ kernel_tex_fetch(__attributes_uchar4, corners[1] + desc.offset));
+ float4 f2 = color_uchar4_to_float4(
+ kernel_tex_fetch(__attributes_uchar4, corners[2] + desc.offset));
+ float4 f3 = color_uchar4_to_float4(
+ kernel_tex_fetch(__attributes_uchar4, corners[3] + desc.offset));
+
+ if (subd_triangle_patch_num_corners(kg, patch) != 4) {
+ f1 = (f1 + f0) * 0.5f;
+ f3 = (f3 + f0) * 0.5f;
+ }
+
+ float4 a = mix(mix(f0, f1, uv[0].x), mix(f3, f2, uv[0].x), uv[0].y);
+ float4 b = mix(mix(f0, f1, uv[1].x), mix(f3, f2, uv[1].x), uv[1].y);
+ float4 c = mix(mix(f0, f1, uv[2].x), mix(f3, f2, uv[2].x), uv[2].y);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * a + sd->dv.dx * b - (sd->du.dx + sd->dv.dx) * c;
+ if (dy)
+ *dy = sd->du.dy * a + sd->dv.dy * b - (sd->du.dy + sd->dv.dy) * c;
+#endif
+
+ return sd->u * a + sd->v * b + (1.0f - sd->u - sd->v) * c;
+ }
+ else {
+ if (dx)
+ *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/geom_triangle.h
index 9938c0ba2c3..4eb01906256 100644
--- a/intern/cycles/kernel/geom/geom_triangle.h
+++ b/intern/cycles/kernel/geom/geom_triangle.h
@@ -289,4 +289,36 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals *kg,
}
}
+ccl_device float4 triangle_attribute_float4(KernelGlobals *kg,
+ const ShaderData *sd,
+ const AttributeDescriptor desc,
+ float4 *dx,
+ float4 *dy)
+{
+ if (desc.element == ATTR_ELEMENT_CORNER_BYTE) {
+ int tri = desc.offset + sd->prim * 3;
+
+ float4 f0 = color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 0));
+ float4 f1 = color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 1));
+ float4 f2 = color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, tri + 2));
+
+#ifdef __RAY_DIFFERENTIALS__
+ if (dx)
+ *dx = sd->du.dx * f0 + sd->dv.dx * f1 - (sd->du.dx + sd->dv.dx) * f2;
+ if (dy)
+ *dy = sd->du.dy * f0 + sd->dv.dy * f1 - (sd->du.dy + sd->dv.dy) * f2;
+#endif
+
+ return sd->u * f0 + sd->v * f1 + (1.0f - sd->u - sd->v) * f2;
+ }
+ else {
+ if (dx)
+ *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ if (dy)
+ *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h
index 78eafbfe3cb..a5ae427c2d3 100644
--- a/intern/cycles/kernel/kernel_random.h
+++ b/intern/cycles/kernel/kernel_random.h
@@ -130,7 +130,7 @@ ccl_device_inline void path_rng_init(KernelGlobals *kg,
float *fy)
{
/* load state */
- *rng_hash = hash_int_2d(x, y);
+ *rng_hash = hash_uint2(x, y);
*rng_hash ^= kernel_data.integrator.seed;
#ifdef __DEBUG_CORRELATION__
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index a1d950bbc70..f1ef37b7cf5 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -1408,6 +1408,7 @@ typedef struct KernelObject {
float surface_area;
float pass_id;
float random_number;
+ float color[3];
int particle_index;
float dupli_generated[3];
@@ -1420,11 +1421,9 @@ typedef struct KernelObject {
uint patch_map_offset;
uint attribute_map_offset;
uint motion_offset;
- uint pad1;
float cryptomatte_object;
float cryptomatte_asset;
- float pad2, pad3;
} KernelObject;
static_assert_align(KernelObject, 16);
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 316d24b0954..13078639586 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -81,6 +81,7 @@ ustring OSLRenderServices::u_screen("screen");
ustring OSLRenderServices::u_raster("raster");
ustring OSLRenderServices::u_ndc("NDC");
ustring OSLRenderServices::u_object_location("object:location");
+ustring OSLRenderServices::u_object_color("object:color");
ustring OSLRenderServices::u_object_index("object:index");
ustring OSLRenderServices::u_geom_dupli_generated("geom:dupli_generated");
ustring OSLRenderServices::u_geom_dupli_uv("geom:dupli_uv");
@@ -482,6 +483,65 @@ static bool set_attribute_float3(float3 f, TypeDesc type, bool derivatives, void
return set_attribute_float3(fv, type, derivatives, val);
}
+/* Attributes with the TypeRGBA type descriptor should be retrived and stored
+ * in a float array of size 4 (e.g. node_vertex_color.osl), this array have
+ * a type descriptor TypeFloatArray4. If the storage is not a TypeFloatArray4,
+ * we either store the first three components in a vector, store the average of
+ * the components in a float, or fail the retrival and do nothing. We allow
+ * this for the correct operation of the Attribute node.
+ */
+
+static bool set_attribute_float4(float4 f[3], TypeDesc type, bool derivatives, void *val)
+{
+ float *fval = (float *)val;
+ if (type == TypeFloatArray4) {
+ fval[0] = f[0].x;
+ fval[1] = f[0].y;
+ fval[2] = f[0].z;
+ fval[3] = f[0].w;
+
+ if (derivatives) {
+ fval[4] = f[1].x;
+ fval[5] = f[1].y;
+ fval[6] = f[1].z;
+ fval[7] = f[1].w;
+
+ fval[8] = f[2].x;
+ fval[9] = f[2].y;
+ fval[10] = f[2].z;
+ fval[11] = f[2].w;
+ }
+ return true;
+ }
+ else if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
+ type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) {
+ fval[0] = f[0].x;
+ fval[1] = f[0].y;
+ fval[2] = f[0].z;
+
+ if (derivatives) {
+ fval[3] = f[1].x;
+ fval[4] = f[1].y;
+ fval[5] = f[1].z;
+
+ fval[6] = f[2].x;
+ fval[7] = f[2].y;
+ fval[8] = f[2].z;
+ }
+ return true;
+ }
+ else if (type == TypeDesc::TypeFloat) {
+ fval[0] = average_float4(f[0]);
+
+ if (derivatives) {
+ fval[1] = average_float4(f[1]);
+ fval[2] = average_float4(f[2]);
+ }
+ return true;
+ }
+ return false;
+}
+
static bool set_attribute_float(float f[3], TypeDesc type, bool derivatives, void *val)
{
if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
@@ -628,6 +688,12 @@ static bool get_primitive_attribute(KernelGlobals *kg,
kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
return set_attribute_float(fval, type, derivatives, val);
}
+ else if (attr.type == TypeRGBA) {
+ float4 fval[3];
+ fval[0] = primitive_attribute_float4(
+ kg, sd, attr.desc, (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
+ return set_attribute_float4(fval, type, derivatives, val);
+ }
else {
return false;
}
@@ -668,6 +734,10 @@ bool OSLRenderServices::get_object_standard_attribute(
float3 f = object_location(kg, sd);
return set_attribute_float3(f, type, derivatives, val);
}
+ else if (name == u_object_color) {
+ float3 f = object_color(kg, sd->object);
+ return set_attribute_float3(f, type, derivatives, val);
+ }
else if (name == u_object_index) {
float f = object_pass_id(kg, sd->object);
return set_attribute_float(f, type, derivatives, val);
@@ -697,7 +767,7 @@ bool OSLRenderServices::get_object_standard_attribute(
}
else if (name == u_particle_random) {
int particle_id = object_particle_id(kg, sd->object);
- float f = hash_int_01(particle_index(kg, particle_id));
+ float f = hash_uint_to_float(particle_index(kg, particle_id));
return set_attribute_float(f, type, derivatives, val);
}
diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h
index 024ef656be1..469c5188730 100644
--- a/intern/cycles/kernel/osl/osl_services.h
+++ b/intern/cycles/kernel/osl/osl_services.h
@@ -245,6 +245,7 @@ class OSLRenderServices : public OSL::RendererServices {
static ustring u_raster;
static ustring u_ndc;
static ustring u_object_location;
+ static ustring u_object_color;
static ustring u_object_index;
static ustring u_geom_dupli_generated;
static ustring u_geom_dupli_uv;
diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt
index b42b9b2fe64..3247ae714e0 100644
--- a/intern/cycles/kernel/shaders/CMakeLists.txt
+++ b/intern/cycles/kernel/shaders/CMakeLists.txt
@@ -89,6 +89,10 @@ set(SRC_OSL
node_uv_map.osl
node_principled_bsdf.osl
node_rgb_to_bw.osl
+ node_map_range.osl
+ node_clamp.osl
+ node_white_noise_texture.osl
+ node_vertex_color.osl
)
set(SRC_OSL_HEADERS
@@ -98,6 +102,8 @@ set(SRC_OSL_HEADERS
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_clamp.osl b/intern/cycles/kernel/shaders/node_clamp.osl
new file mode 100644
index 00000000000..43b0fe88172
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_clamp.osl
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdosl.h"
+
+shader node_clamp(float Value = 1.0, float Min = 0.0, float Max = 1.0,
+ output float Result = 0.0)
+{
+ Result = clamp(Value, Min, Max);
+}
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_map_range.osl b/intern/cycles/kernel/shaders/node_map_range.osl
new file mode 100644
index 00000000000..5a753246875
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_map_range.osl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdosl.h"
+
+shader node_map_range(float Value = 1.0, float FromMin = 0.0, float FromMax = 1.0,
+ float ToMin = 0.0, float ToMax = 1.0, output float Result = 0.0)
+{
+ if (FromMax != FromMin) {
+ Result = ToMin + ((Value - FromMin) / (FromMax - FromMin)) * (ToMax - ToMin);
+ }
+ else {
+ Result = 0.0;
+ }
+}
diff --git a/intern/cycles/kernel/shaders/node_mapping.osl b/intern/cycles/kernel/shaders/node_mapping.osl
index f5cc2d1c5dd..98590c64fcc 100644
--- a/intern/cycles/kernel/shaders/node_mapping.osl
+++ b/intern/cycles/kernel/shaders/node_mapping.osl
@@ -16,17 +16,55 @@
#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)
{
- point p = transform(Matrix, VectorIn);
+ 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){
+ matrix mat = matrix(1.0);
+ float c1, c2, c3, s1, s2, s3;
+
+ c1 = cos(euler[0]);
+ c2 = cos(euler[1]);
+ c3 = cos(euler[2]);
+ s1 = sin(euler[0]);
+ s2 = sin(euler[1]);
+ s3 = sin(euler[2]);
+
+ mat[0][0] = c2 * c3;
+ mat[0][1] = c1 * s3 + c3 * s1 * s2;
+ mat[0][2] = s1 * s3 - c1 * c3 * s2;
- if (use_minmax)
- p = min(max(mapping_min, p), mapping_max);
+ mat[1][0] = -c2 * s3;
+ mat[1][1] = c1 * c3 - s1 * s2 * s3;
+ mat[1][2] = c3 * s1 + c1 * s2 * s3;
- VectorOut = p;
+ mat[2][0] = s2;
+ mat[2][1] = -c2 * s1;
+ mat[2][2] = c1 * c2;
+
+ return mat;
+}
+
+shader node_mapping(string type = "point",
+ point Vector = 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 Result = point(0.0, 0.0, 0.0))
+{
+ if (type == "point") {
+ Result = transform(euler_to_mat(Rotation), (Vector * Scale)) + Location;
+ } else if (type == "texture") {
+ Result = safe_divide(transform(euler_to_mat(-Rotation), (Vector - Location)), Scale);
+ } else if (type == "vector") {
+ Result = transform(euler_to_mat(Rotation), (Vector * Scale));
+ } else if (type == "normal") {
+ Result = normalize(transform(euler_to_mat(Rotation), safe_divide(Vector, Scale)));
+ } else {
+ warning("%s", "Unknown Mapping vector type!");
+ }
}
diff --git a/intern/cycles/kernel/shaders/node_math.osl b/intern/cycles/kernel/shaders/node_math.osl
index 8830339e05f..f8c95a7b664 100644
--- a/intern/cycles/kernel/shaders/node_math.osl
+++ b/intern/cycles/kernel/shaders/node_math.osl
@@ -17,106 +17,79 @@
#include "stdosl.h"
float safe_divide(float a, float b)
-{
- float result;
-
- if (b == 0.0)
- result = 0.0;
- else
- result = a / b;
-
- return result;
+{
+ return (b != 0.0) ? a / b : 0.0;
}
float safe_modulo(float a, float b)
{
- float result;
-
- if (b == 0.0)
- result = 0.0;
- else
- result = fmod(a, b);
-
- return result;
+ return (b != 0.0) ? fmod(a, b) : 0.0;
}
float safe_sqrt(float a)
{
- float result;
-
- if (a > 0.0)
- result = sqrt(a);
- else
- result = 0.0;
-
- return result;
+ return (a > 0.0) ? sqrt(a) : 0.0;
}
float safe_log(float a, float b)
{
- if (a < 0.0 || b < 0.0)
- return 0.0;
-
- return log(a) / log(b);
+ return (a > 0.0 && b > 0.0) ? log(a) / log(b) : 0.0;
}
shader node_math(string type = "add",
- int use_clamp = 0,
- float Value1 = 0.0,
- float Value2 = 0.0,
- output float Value = 0.0)
+ float A = 0.5,
+ float B = 0.5,
+ output float Result = 0.0)
{
- /* OSL asin, acos, pow check for values that could give rise to nan */
-
+ /* OSL asin, acos, pow check for values that could give rise to nan. */
if (type == "add")
- Value = Value1 + Value2;
+ Result = A + B;
else if (type == "subtract")
- Value = Value1 - Value2;
+ Result = A - B;
else if (type == "multiply")
- Value = Value1 * Value2;
+ Result = A * B;
else if (type == "divide")
- Value = safe_divide(Value1, Value2);
- else if (type == "sine")
- Value = sin(Value1);
- else if (type == "cosine")
- Value = cos(Value1);
- else if (type == "tangent")
- Value = tan(Value1);
- else if (type == "arcsine")
- Value = asin(Value1);
- else if (type == "arccosine")
- Value = acos(Value1);
- else if (type == "arctangent")
- Value = atan(Value1);
+ Result = safe_divide(A, B);
else if (type == "power")
- Value = pow(Value1, Value2);
+ Result = pow(A, B);
else if (type == "logarithm")
- Value = safe_log(Value1, Value2);
+ Result = safe_log(A, B);
+ else if (type == "sqrt")
+ Result = safe_sqrt(A);
+ else if (type == "absolute")
+ Result = fabs(A);
else if (type == "minimum")
- Value = min(Value1, Value2);
+ Result = min(A, B);
else if (type == "maximum")
- Value = max(Value1, Value2);
- else if (type == "round")
- Value = floor(Value1 + 0.5);
+ Result = max(A, B);
else if (type == "less_than")
- Value = Value1 < Value2;
+ Result = A < B;
else if (type == "greater_than")
- Value = Value1 > Value2;
- else if (type == "modulo")
- Value = safe_modulo(Value1, Value2);
- else if (type == "absolute")
- Value = fabs(Value1);
- else if (type == "arctan2")
- Value = atan2(Value1, Value2);
+ Result = A > B;
+ else if (type == "round")
+ Result = floor(A + 0.5);
else if (type == "floor")
- Value = floor(Value1);
+ Result = floor(A);
else if (type == "ceil")
- Value = ceil(Value1);
- else if (type == "fract")
- Value = Value1 - floor(Value1);
- else if (type == "sqrt")
- Value = safe_sqrt(Value1);
-
- if (use_clamp)
- Value = clamp(Value, 0.0, 1.0);
+ Result = ceil(A);
+ else if (type == "fraction")
+ Result = A - floor(A);
+ else if (type == "modulo")
+ Result = safe_modulo(A, B);
+ else if (type == "sine")
+ Result = sin(A);
+ else if (type == "cosine")
+ Result = cos(A);
+ else if (type == "tangent")
+ Result = tan(A);
+ else if (type == "arcsine")
+ Result = asin(A);
+ else if (type == "arccosine")
+ Result = acos(A);
+ else if (type == "arctangent")
+ Result = atan(A);
+ else if (type == "arctan2")
+ Result = atan2(A, B);
+ else
+ Result = 0.0;
}
diff --git a/intern/cycles/kernel/shaders/node_musgrave_texture.osl b/intern/cycles/kernel/shaders/node_musgrave_texture.osl
index a7877c43d46..1ef10035891 100644
--- a/intern/cycles/kernel/shaders/node_musgrave_texture.osl
+++ b/intern/cycles/kernel/shaders/node_musgrave_texture.osl
@@ -16,8 +16,342 @@
#include "stdosl.h"
#include "node_texture.h"
+#include "vector2.h"
+#include "vector4.h"
-/* Musgrave fBm
+#define vector3 point
+
+/* 1D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+float noise_musgrave_fBm_1d(float p, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += safe_snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * safe_snoise(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 1D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal_1d(float p, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * safe_snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */
+ }
+
+ return value;
+}
+
+/* 1D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hetero_terrain_1d(
+ float p, float H, float lacunarity, float octaves, float offset)
+{
+ float value, increment, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + safe_snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ increment = (safe_snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ increment = (safe_snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 1D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hybrid_multi_fractal_1d(
+ float p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ result = safe_snoise(p) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ signal = (safe_snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ result += rmd * ((safe_snoise(p) + offset) * pwr);
+ }
+
+ return result;
+}
+
+/* 1D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_ridged_multi_fractal_1d(
+ float p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ result = signal;
+ weight = 1.0;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return result;
+}
+
+/* 2D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+float noise_musgrave_fBm_2d(vector2 p, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += safe_snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * safe_snoise(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 2D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal_2d(vector2 p, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * safe_snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */
+ }
+
+ return value;
+}
+
+/* 2D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hetero_terrain_2d(
+ vector2 p, float H, float lacunarity, float octaves, float offset)
+{
+ float value, increment, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + safe_snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ increment = (safe_snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ increment = (safe_snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 2D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hybrid_multi_fractal_2d(
+ vector2 p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ result = safe_snoise(p) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ signal = (safe_snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ result += rmd * ((safe_snoise(p) + offset) * pwr);
+ }
+
+ return result;
+}
+
+/* 2D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_ridged_multi_fractal_2d(
+ vector2 p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ result = signal;
+ weight = 1.0;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return result;
+}
+
+/* 3D Musgrave fBm
*
* H: fractal increment parameter
* lacunarity: gap between successive frequencies
@@ -26,58 +360,56 @@
* from "Texturing and Modelling: A procedural approach"
*/
-float noise_musgrave_fBm(point ip, float H, float lacunarity, float octaves)
+float noise_musgrave_fBm_3d(vector3 p, float H, float lacunarity, float octaves)
{
float rmd;
float value = 0.0;
float pwr = 1.0;
float pwHL = pow(lacunarity, -H);
- int i;
- point p = ip;
- for (i = 0; i < (int)octaves; i++) {
- value += safe_noise(p, "signed") * pwr;
+ for (int i = 0; i < (int)octaves; i++) {
+ value += safe_snoise(p) * pwr;
pwr *= pwHL;
p *= lacunarity;
}
rmd = octaves - floor(octaves);
- if (rmd != 0.0)
- value += rmd * safe_noise(p, "signed") * pwr;
+ if (rmd != 0.0) {
+ value += rmd * safe_snoise(p) * pwr;
+ }
return value;
}
-/* Musgrave Multifractal
+/* 3D Musgrave Multifractal
*
* H: highest fractal dimension
* lacunarity: gap between successive frequencies
* octaves: number of frequencies in the fBm
*/
-float noise_musgrave_multi_fractal(point ip, float H, float lacunarity, float octaves)
+float noise_musgrave_multi_fractal_3d(vector3 p, float H, float lacunarity, float octaves)
{
float rmd;
float value = 1.0;
float pwr = 1.0;
float pwHL = pow(lacunarity, -H);
- int i;
- point p = ip;
- for (i = 0; i < (int)octaves; i++) {
- value *= (pwr * safe_noise(p, "signed") + 1.0);
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * safe_snoise(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? */
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */
+ }
return value;
}
-/* Musgrave Heterogeneous Terrain
+/* 3D Musgrave Heterogeneous Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -85,21 +417,19 @@ float noise_musgrave_multi_fractal(point ip, float H, float lacunarity, float oc
* offset: raises the terrain from `sea level'
*/
-float noise_musgrave_hetero_terrain(
- point ip, float H, float lacunarity, float octaves, float offset)
+float noise_musgrave_hetero_terrain_3d(
+ vector3 p, float H, float lacunarity, float octaves, float offset)
{
float value, increment, rmd;
float pwHL = pow(lacunarity, -H);
float pwr = pwHL;
- int i;
- point p = ip;
/* first unscaled octave of function; later octaves are scaled */
- value = offset + safe_noise(p, "signed");
+ value = offset + safe_snoise(p);
p *= lacunarity;
- for (i = 1; i < (int)octaves; i++) {
- increment = (safe_noise(p, "signed") + offset) * pwr * value;
+ for (int i = 1; i < (int)octaves; i++) {
+ increment = (safe_snoise(p) + offset) * pwr * value;
value += increment;
pwr *= pwHL;
p *= lacunarity;
@@ -107,14 +437,14 @@ float noise_musgrave_hetero_terrain(
rmd = octaves - floor(octaves);
if (rmd != 0.0) {
- increment = (safe_noise(p, "signed") + offset) * pwr * value;
+ increment = (safe_snoise(p) + offset) * pwr * value;
value += rmd * increment;
}
return value;
}
-/* Hybrid Additive/Multiplicative Multifractal Terrain
+/* 3D Hybrid Additive/Multiplicative Multifractal Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -122,24 +452,23 @@ float noise_musgrave_hetero_terrain(
* offset: raises the terrain from `sea level'
*/
-float noise_musgrave_hybrid_multi_fractal(
- point ip, float H, float lacunarity, float octaves, float offset, float gain)
+float noise_musgrave_hybrid_multi_fractal_3d(
+ vector3 p, float H, float lacunarity, float octaves, float offset, float gain)
{
float result, signal, weight, rmd;
float pwHL = pow(lacunarity, -H);
float pwr = pwHL;
- int i;
- point p = ip;
- result = safe_noise(p, "signed") + offset;
+ result = safe_snoise(p) + offset;
weight = gain * result;
p *= lacunarity;
- for (i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
- if (weight > 1.0)
+ for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if (weight > 1.0) {
weight = 1.0;
+ }
- signal = (safe_noise(p, "signed") + offset) * pwr;
+ signal = (safe_snoise(p) + offset) * pwr;
pwr *= pwHL;
result += weight * signal;
weight *= gain * signal;
@@ -147,13 +476,14 @@ float noise_musgrave_hybrid_multi_fractal(
}
rmd = octaves - floor(octaves);
- if (rmd != 0.0)
- result += rmd * ((safe_noise(p, "signed") + offset) * pwr);
+ if (rmd != 0.0) {
+ result += rmd * ((safe_snoise(p) + offset) * pwr);
+ }
return result;
}
-/* Ridged Multifractal Terrain
+/* 3D Ridged Multifractal Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -161,24 +491,22 @@ float noise_musgrave_hybrid_multi_fractal(
* offset: raises the terrain from `sea level'
*/
-float noise_musgrave_ridged_multi_fractal(
- point ip, float H, float lacunarity, float octaves, float offset, float gain)
+float noise_musgrave_ridged_multi_fractal_3d(
+ vector3 p, float H, float lacunarity, float octaves, float offset, float gain)
{
float result, signal, weight;
float pwHL = pow(lacunarity, -H);
float pwr = pwHL;
- int i;
- point p = ip;
- signal = offset - fabs(safe_noise(p, "signed"));
+ signal = offset - fabs(safe_snoise(p));
signal *= signal;
result = signal;
weight = 1.0;
- for (i = 1; i < (int)octaves; i++) {
+ for (int 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_snoise(p));
signal *= signal;
signal *= weight;
result += signal * pwr;
@@ -188,46 +516,288 @@ float noise_musgrave_ridged_multi_fractal(
return result;
}
-/* Shader */
+/* 4D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+float noise_musgrave_fBm_4d(vector4 p, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value += safe_snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * safe_snoise(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 4D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal_4d(vector4 p, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < (int)octaves; i++) {
+ value *= (pwr * safe_snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * safe_snoise(p) + 1.0); /* correct? */
+ }
+
+ return value;
+}
+
+/* 4D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hetero_terrain_4d(
+ vector4 p, float H, float lacunarity, float octaves, float offset)
+{
+ float value, increment, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + safe_snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ increment = (safe_snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ increment = (safe_snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 4D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hybrid_multi_fractal_4d(
+ vector4 p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ result = safe_snoise(p) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ signal = (safe_snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ result += rmd * ((safe_snoise(p) + offset) * pwr);
+ }
+
+ return result;
+}
+
+/* 4D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_ridged_multi_fractal_4d(
+ vector4 p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ result = signal;
+ weight = 1.0;
+
+ for (int i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - fabs(safe_snoise(p));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return result;
+}
shader node_musgrave_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
string type = "fBM",
+ string dimensions = "3D",
+ point Vector = P,
+ float W = 0.0,
float Dimension = 2.0,
- float Lacunarity = 1.0,
+ float Scale = 5.0,
float Detail = 2.0,
+ float Lacunarity = 1.0,
float Offset = 0.0,
float Gain = 1.0,
- float Scale = 5.0,
- point Vector = P,
- output float Fac = 0.0,
- output color Color = 0.0)
+ output float Fac = 0.0)
{
float dimension = max(Dimension, 1e-5);
float octaves = clamp(Detail, 0.0, 16.0);
float lacunarity = max(Lacunarity, 1e-5);
- float intensity = 1.0;
- point p = Vector;
+ vector3 s = Vector;
if (use_mapping)
- p = transform(mapping, p);
-
- p = p * Scale;
-
- if (type == "multifractal")
- Fac = intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
- else if (type == "fBM")
- Fac = intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
- else if (type == "hybrid_multifractal")
- Fac = intensity *
- noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain);
- else if (type == "ridged_multifractal")
- Fac = intensity *
- noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, Offset, Gain);
- else if (type == "hetero_terrain")
- Fac = intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, Offset);
-
- Color = color(Fac, Fac, Fac);
+ s = transform(mapping, s);
+
+ if (dimensions == "1D") {
+ float p = W * Scale;
+ if (type == "multifractal") {
+ Fac = noise_musgrave_multi_fractal_1d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "fBM") {
+ Fac = noise_musgrave_fBm_1d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "hybrid_multifractal") {
+ Fac = noise_musgrave_hybrid_multi_fractal_1d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "ridged_multifractal") {
+ Fac = noise_musgrave_ridged_multi_fractal_1d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "hetero_terrain") {
+ Fac = noise_musgrave_hetero_terrain_1d(p, dimension, lacunarity, octaves, Offset);
+ }
+ else {
+ Fac = 0.0;
+ }
+ }
+ else if (dimensions == "2D") {
+ vector2 p = vector2(s[0], s[1]) * Scale;
+ if (type == "multifractal") {
+ Fac = noise_musgrave_multi_fractal_2d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "fBM") {
+ Fac = noise_musgrave_fBm_2d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "hybrid_multifractal") {
+ Fac = noise_musgrave_hybrid_multi_fractal_2d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "ridged_multifractal") {
+ Fac = noise_musgrave_ridged_multi_fractal_2d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "hetero_terrain") {
+ Fac = noise_musgrave_hetero_terrain_2d(p, dimension, lacunarity, octaves, Offset);
+ }
+ else {
+ Fac = 0.0;
+ }
+ }
+ else if (dimensions == "3D") {
+ vector3 p = s * Scale;
+ if (type == "multifractal") {
+ Fac = noise_musgrave_multi_fractal_3d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "fBM") {
+ Fac = noise_musgrave_fBm_3d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "hybrid_multifractal") {
+ Fac = noise_musgrave_hybrid_multi_fractal_3d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "ridged_multifractal") {
+ Fac = noise_musgrave_ridged_multi_fractal_3d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "hetero_terrain") {
+ Fac = noise_musgrave_hetero_terrain_3d(p, dimension, lacunarity, octaves, Offset);
+ }
+ else {
+ Fac = 0.0;
+ }
+ }
+ else if (dimensions == "4D") {
+ vector4 p = vector4(s[0], s[1], s[2], W) * Scale;
+ if (type == "multifractal") {
+ Fac = noise_musgrave_multi_fractal_4d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "fBM") {
+ Fac = noise_musgrave_fBm_4d(p, dimension, lacunarity, octaves);
+ }
+ else if (type == "hybrid_multifractal") {
+ Fac = noise_musgrave_hybrid_multi_fractal_4d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "ridged_multifractal") {
+ Fac = noise_musgrave_ridged_multi_fractal_4d(
+ p, dimension, lacunarity, octaves, Offset, Gain);
+ }
+ else if (type == "hetero_terrain") {
+ Fac = noise_musgrave_hetero_terrain_4d(p, dimension, lacunarity, octaves, Offset);
+ }
+ else {
+ Fac = 0.0;
+ }
+ }
+ else {
+ Fac = 0.0;
+ }
}
diff --git a/intern/cycles/kernel/shaders/node_noise_texture.osl b/intern/cycles/kernel/shaders/node_noise_texture.osl
index 2cbd571e206..6e68017596c 100644
--- a/intern/cycles/kernel/shaders/node_noise_texture.osl
+++ b/intern/cycles/kernel/shaders/node_noise_texture.osl
@@ -15,46 +15,133 @@
*/
#include "stdosl.h"
+#include "vector2.h"
+#include "vector4.h"
#include "node_texture.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 = noise_turbulence(p, detail);
+ Color = color(value,
+ noise_turbulence(p + random_float_offset(1.0), detail),
+ noise_turbulence(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 = noise_turbulence(p, detail);
+ Color = color(value,
+ noise_turbulence(p + random_vector2_offset(2.0), detail),
+ noise_turbulence(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 = noise_turbulence(p, detail);
+ Color = color(value,
+ noise_turbulence(p + random_vector3_offset(3.0), detail),
+ noise_turbulence(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 = noise_turbulence(p, detail);
+ Color = color(value,
+ noise_turbulence(p + random_vector4_offset(4.0), detail),
+ noise_turbulence(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,
- output float Fac = 0.0,
+ float Distortion = 0.0,
+ output float Value = 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")
+ Value = noise_texture(w, Detail, Distortion, Color);
+ else if (dimensions == "2D")
+ Value = noise_texture(vector2(p[0], p[1]), Detail, Distortion, Color);
+ else if (dimensions == "3D")
+ Value = noise_texture(p, Detail, Distortion, Color);
+ else if (dimensions == "4D")
+ Value = 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_object_info.osl b/intern/cycles/kernel/shaders/node_object_info.osl
index 0904a30a53f..350404bb747 100644
--- a/intern/cycles/kernel/shaders/node_object_info.osl
+++ b/intern/cycles/kernel/shaders/node_object_info.osl
@@ -17,11 +17,13 @@
#include "stdosl.h"
shader node_object_info(output point Location = point(0.0, 0.0, 0.0),
+ output color Color = color(1.0, 1.0, 1.0),
output float ObjectIndex = 0.0,
output float MaterialIndex = 0.0,
output float Random = 0.0)
{
getattribute("object:location", Location);
+ getattribute("object:color", Color);
getattribute("object:index", ObjectIndex);
getattribute("material:index", MaterialIndex);
getattribute("object:random", Random);
diff --git a/intern/cycles/kernel/shaders/node_texture.h b/intern/cycles/kernel/shaders/node_texture.h
index e1f3b900ee5..7089f52d9a6 100644
--- a/intern/cycles/kernel/shaders/node_texture.h
+++ b/intern/cycles/kernel/shaders/node_texture.h
@@ -14,134 +14,106 @@
* limitations under the License.
*/
-/* Voronoi / Worley like */
+#include "vector2.h"
+#include "vector4.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]));
+#define vector3 point
+
+/* Safe versions of unsigned perlin noise. Noise can be infinit at large coordinates.
+ * The noise approachs 0.5 at large coordinates.
+ */
- return color(r, g, b);
+float safe_noise(float p)
+{
+ float f = noise("noise", p);
+ if (isinf(f))
+ return 0.5;
+ return f;
}
-void voronoi(point p, float e, float da[4], point pa[4])
+float safe_noise(vector2 p)
{
- /* 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;
- }
- }
- }
- }
+ float f = noise("noise", p.x, p.y);
+ if (isinf(f))
+ return 0.5;
+ return f;
}
-/* Noise Bases */
+float safe_noise(vector3 p)
+{
+ float f = noise("noise", p);
+ if (isinf(f))
+ return 0.5;
+ return f;
+}
-float safe_noise(point p, string type)
+float safe_noise(vector4 p)
{
- float f = 0.0;
+ float f = noise("noise", vector3(p.x, p.y, p.z), p.w);
+ if (isinf(f))
+ return 0.5;
+ return f;
+}
- /* Perlin noise in range -1..1 */
- if (type == "signed")
- f = noise("perlin", p);
+/* Safe versions of signed perlin noise. Noise can be infinit at large coordinates.
+ * The noise approachs 0.0 at large coordinates.
+ */
- /* Perlin noise in range 0..1 */
- else
- f = noise(p);
+float safe_snoise(float p)
+{
+ float f = noise("snoise", p);
+ if (isinf(f))
+ return 0.0;
+ return f;
+}
- /* can happen for big coordinates, things even out to 0.5 then anyway */
- if (!isfinite(f))
- return 0.5;
+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;
}
-/* Turbulence */
+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 following 4 functions are exactly the same but with different input type.
+ * When refactoring, simply copy the function body to the rest of the functions.
+ */
-float noise_turbulence(point p, float details, int hard)
+float noise_turbulence(float p, float details)
{
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);
-
+ 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, "unsigned");
-
- if (hard)
- t = fabs(2.0 * t - 1.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 {
@@ -150,16 +122,83 @@ float noise_turbulence(point p, float details, int hard)
}
}
-/* Utility */
-
-float nonzero(float f, float eps)
+float noise_turbulence(vector2 p, float details)
{
- float r;
+ 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;
+ }
+}
- if (abs(f) < eps)
- r = sign(f) * eps;
- else
- r = f;
+float noise_turbulence(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;
+ }
+}
- return r;
+float noise_turbulence(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;
+ }
}
diff --git a/intern/cycles/kernel/shaders/node_vector_math.osl b/intern/cycles/kernel/shaders/node_vector_math.osl
index 10bb0c7283c..20683067eed 100644
--- a/intern/cycles/kernel/shaders/node_vector_math.osl
+++ b/intern/cycles/kernel/shaders/node_vector_math.osl
@@ -16,34 +16,99 @@
#include "stdosl.h"
+float safe_divide(float a, float b)
+{
+ return (b != 0.0) ? a / b : 0.0;
+}
+
+vector safe_divide(vector a, vector b)
+{
+ return vector((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);
+}
+
+vector project(vector v, vector v_proj)
+{
+ float lenSquared = dot(v_proj, v_proj);
+ return (lenSquared != 0.0) ? (dot(v, v_proj) / lenSquared) * v_proj : vector(0.0);
+}
+
+vector snap(vector a, vector b)
+{
+ return vector(floor(safe_divide(a[0], b[0])) * b[0],
+ floor(safe_divide(a[1], b[1])) * b[1],
+ floor(safe_divide(a[2], b[2])) * b[2]);
+}
+
shader node_vector_math(string type = "add",
- vector Vector1 = vector(0.0, 0.0, 0.0),
- vector Vector2 = vector(0.0, 0.0, 0.0),
+ vector A = vector(0.0, 0.0, 0.0),
+ vector B = vector(0.0, 0.0, 0.0),
+ float Scale = 1.0,
output float Value = 0.0,
output vector Vector = vector(0.0, 0.0, 0.0))
{
if (type == "add") {
- Vector = Vector1 + Vector2;
- Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0;
+ Vector = A + B;
}
else if (type == "subtract") {
- Vector = Vector1 - Vector2;
- Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0;
+ Vector = A - B;
}
- else if (type == "average") {
- Value = length(Vector1 + Vector2);
- Vector = normalize(Vector1 + Vector2);
+ else if (type == "multiply") {
+ Vector = A * B;
}
- else if (type == "dot_product") {
- Value = dot(Vector1, Vector2);
+ else if (type == "divide") {
+ Vector = safe_divide(A, B);
}
else if (type == "cross_product") {
- vector c = cross(Vector1, Vector2);
- Value = length(c);
- Vector = normalize(c);
+ Vector = cross(A, B);
+ }
+ else if (type == "project") {
+ Vector = project(A, B);
+ }
+ else if (type == "reflect") {
+ Vector = reflect(A, B);
+ }
+ else if (type == "dot_product") {
+ Value = dot(A, B);
+ }
+ else if (type == "distance") {
+ Value = distance(A, B);
+ }
+ else if (type == "length") {
+ Value = length(A);
+ }
+ else if (type == "scale") {
+ Vector = A * Scale;
}
else if (type == "normalize") {
- Value = length(Vector1);
- Vector = normalize(Vector1);
+ Vector = normalize(A);
+ }
+ else if (type == "snap") {
+ Vector = snap(A, B);
+ }
+ else if (type == "floor") {
+ Vector = floor(A);
+ }
+ else if (type == "ceil") {
+ Vector = ceil(A);
+ }
+ else if (type == "modulo") {
+ Vector = mod(A, B);
+ }
+ else if (type == "fraction") {
+ Vector = A - floor(A);
+ }
+ else if (type == "absolute") {
+ Vector = abs(A);
+ }
+ else if (type == "minimum") {
+ Vector = min(A, B);
+ }
+ else if (type == "maximum") {
+ Vector = max(A, B);
+ }
+ else {
+ warning("%s", "Unknown vector math operator!");
}
}
diff --git a/intern/cycles/kernel/shaders/node_vertex_color.osl b/intern/cycles/kernel/shaders/node_vertex_color.osl
new file mode 100644
index 00000000000..1997a690181
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_vertex_color.osl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdosl.h"
+
+shader node_vertex_color(string bump_offset = "center",
+ string layer_name = "",
+ output color Color = 0.0,
+ output float Alpha = 0.0)
+{
+ float vertex_color[4];
+ if (getattribute(layer_name, vertex_color)) {
+ Color = color(vertex_color[0], vertex_color[1], vertex_color[2]);
+ Alpha = vertex_color[3];
+
+ if (bump_offset == "dx") {
+ Color += Dx(Color);
+ Alpha += Dx(Alpha);
+ }
+ else if (bump_offset == "dy") {
+ Color += Dy(Color);
+ Alpha += Dy(Alpha);
+ }
+ } else {
+ warning("%s", "Invalid attribute.");
+ }
+}
diff --git a/intern/cycles/kernel/shaders/node_voronoi_texture.osl b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
index 34c86d5b98d..651f9fc5b43 100644
--- a/intern/cycles/kernel/shaders/node_voronoi_texture.osl
+++ b/intern/cycles/kernel/shaders/node_voronoi_texture.osl
@@ -15,150 +15,1029 @@
*/
#include "stdosl.h"
-#include "node_texture.h"
-
-void voronoi_m(point p, string metric, float e, float da[4], point pa[4])
-{
- /* Compute the distance to and the position of the four closest neighbors to p.
- *
- * The neighbors are randomly placed, 1 each in a 3x3x3 grid (Worley pattern).
- * The distances and points are returned in ascending order, i.e. da[0] and pa[0] will
- * contain the distance to the closest point and its coordinates respectively.
- */
- 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 = 0.0;
- if (metric == "distance") {
- d = dot(pd, pd);
+#include "vector2.h"
+#include "vector4.h"
+
+#define vector3 point
+
+/* **** Hash a float or vector[234] into a float [0, 1] **** */
+
+float hash_01(float k)
+{
+ return hashnoise(k);
+}
+
+float hash_01(vector2 k)
+{
+ return hashnoise(k.x, k.y);
+}
+
+float hash_01(vector3 k)
+{
+ return hashnoise(k);
+}
+
+float hash_01(vector4 k)
+{
+ return hashnoise(vector3(k.x, k.y, k.z), k.w);
+}
+
+/* **** Hash a vector[234] into a vector[234] [0, 1] **** */
+
+vector2 hash_01_vector2(vector2 k)
+{
+ return vector2(hash_01(k), hash_01(vector3(k.x, k.y, 1.0)));
+}
+
+vector3 hash_01_vector3(vector3 k)
+{
+ return vector3(hash_01(k),
+ hash_01(vector4(k[0], k[1], k[2], 1.0)),
+ hash_01(vector4(k[0], k[1], k[2], 2.0)));
+}
+
+vector4 hash_01_vector4(vector4 k)
+{
+ return vector4(hash_01(k),
+ hash_01(vector4(k.w, k.x, k.y, k.z)),
+ hash_01(vector4(k.z, k.w, k.x, k.y)),
+ hash_01(vector4(k.y, k.z, k.w, k.x)));
+}
+
+/* **** Hash a float or a vec[234] into a color [0, 1] **** */
+
+color hash_01_color(float k)
+{
+ return color(hash_01(k), hash_01(vector2(k, 1.0)), hash_01(vector2(k, 2.0)));
+}
+
+color hash_01_color(vector2 k)
+{
+ return color(hash_01(k), hash_01(vector3(k.x, k.y, 1.0)), hash_01(vector3(k.x, k.y, 2.0)));
+}
+
+color hash_01_color(vector3 k)
+{
+ return color(hash_01(k),
+ hash_01(vector4(k[0], k[1], k[2], 1.0)),
+ hash_01(vector4(k[0], k[1], k[2], 2.0)));
+}
+
+color hash_01_color(vector4 k)
+{
+ return color(
+ hash_01(k), hash_01(vector4(k.z, k.x, k.w, k.y)), hash_01(vector4(k.w, k.z, k.y, k.x)));
+}
+
+/* **** Distance Functions **** */
+
+float distance(float a, float b)
+{
+ return abs(a - b);
+}
+
+float distance(vector2 a, vector2 b)
+{
+ return length(a - b);
+}
+
+float distance(vector4 a, vector4 b)
+{
+ return length(a - b);
+}
+
+/* **** Safe Division **** */
+
+// OSL ternary operator only works with floats for some reason.
+
+vector2 safe_divide(vector2 a, float b)
+{
+ return vector2((b != 0.0) ? a.x / b : 0.0, (b != 0.0) ? a.y / b : 0.0);
+}
+
+vector4 safe_divide(vector4 a, float b)
+{
+ return vector4((b != 0.0) ? a.x / b : 0.0,
+ (b != 0.0) ? a.y / b : 0.0,
+ (b != 0.0) ? a.z / b : 0.0,
+ (b != 0.0) ? a.w / b : 0.0);
+}
+
+/* **** Voronoi Texture **** */
+
+// Each of the following functions computes a certain voronoi feature in a certain dimension.
+// Independent functions are used because every feature/dimension have a different search area.
+//
+// This code is based on the following:
+// Base code : http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm
+// Smoothing : https://iquilezles.untergrund.net/www/articles/smin/smin.htm
+// Distance To Edge Method : https://www.shadertoy.com/view/llG3zy
+
+/* **** 1D Voronoi **** */
+
+float voronoi_distance(float a, float b, string metric, float exponent)
+{
+ return abs(a - b);
+}
+
+void voronoi_f1_1d(float w,
+ float exponent,
+ float jitter,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output float outW)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - cellPosition;
+
+ float minDistance = 8.0;
+ float targetOffset, targetPosition;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_01(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ outDistance = minDistance;
+ outColor = hash_01_color(cellPosition + targetOffset);
+ outW = targetPosition + cellPosition;
+}
+
+void voronoi_smooth_f1_1d(float w,
+ float smoothness,
+ float exponent,
+ float jitter,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output float outW)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - cellPosition;
+
+ float smoothDistance = 0.0;
+ float smoothPosition = 0.0;
+ color smoothColor = color(0.0);
+ for (int i = -2; i <= 2; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_01(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float weight = exp(-smoothness * distanceToPoint);
+ smoothDistance += weight;
+ smoothColor += hash_01_color(cellPosition + cellOffset) * weight;
+ smoothPosition += pointPosition * weight;
+ }
+ outDistance = -log(smoothDistance) / smoothness;
+ outColor = smoothColor / smoothDistance;
+ outW = cellPosition + smoothPosition / smoothDistance;
+}
+
+void voronoi_f2_1d(float w,
+ float exponent,
+ float jitter,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output float outW)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ float offsetF1 = 0.0;
+ float positionF1 = 0.0;
+ float offsetF2, positionF2;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_01(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ outDistance = distanceF2;
+ outColor = hash_01_color(cellPosition + offsetF2);
+ outW = positionF2 + cellPosition;
+}
+
+void voronoi_distance_to_edge_1d(float w, float jitter, output float outDistance)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - cellPosition;
+
+ float minDistance = 8.0;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_01(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ minDistance = min(distanceToPoint, minDistance);
+ }
+ outDistance = minDistance;
+}
+
+void voronoi_n_sphere_radius_1d(float w, float jitter, output float outRadius)
+{
+ float cellPosition = floor(w);
+ float localPosition = w - cellPosition;
+
+ float closestPoint;
+ float closestPointOffset;
+ float minDistance = 8.0;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_01(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+
+ minDistance = 8.0;
+ float closestPointToClosestPoint;
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0)
+ continue;
+ float cellOffset = float(i) + closestPointOffset;
+ float pointPosition = cellOffset + hash_01(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 2D Voronoi **** */
+
+float voronoi_distance(vector2 a, vector2 b, string metric, float exponent)
+{
+ if (metric == "euclidean")
+ return distance(a, b);
+ else if (metric == "manhattan")
+ return abs(a.x - b.x) + abs(a.y - b.y);
+ else if (metric == "chebychev")
+ return max(abs(a.x - b.x), abs(a.y - b.y));
+ else if (metric == "minkowski")
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent), 1.0 / exponent);
+ else
+ return 0.0;
+}
+
+void voronoi_f1_2d(vector2 coord,
+ float exponent,
+ float jitter,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector2 outPosition)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0;
+ vector2 targetOffset, targetPosition;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 pointPosition = cellOffset + hash_01_vector2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor = hash_01_color(cellPosition + targetOffset);
+ outPosition = targetPosition + cellPosition;
+}
+
+void voronoi_smooth_f1_2d(vector2 coord,
+ float smoothness,
+ float exponent,
+ float jitter,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector2 outPosition)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ color smoothColor = color(0.0);
+ float smoothDistance = 0.0;
+ vector2 smoothPosition = vector2(0.0, 0.0);
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 pointPosition = cellOffset + hash_01_vector2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float weight = exp(-smoothness * distanceToPoint);
+ smoothDistance += weight;
+ smoothColor += hash_01_color(cellPosition + cellOffset) * weight;
+ smoothPosition += pointPosition * weight;
+ }
+ }
+ outDistance = -log(smoothDistance) / smoothness;
+ outColor = smoothColor / smoothDistance;
+ outPosition = cellPosition + smoothPosition / smoothDistance;
+}
+
+void voronoi_f2_2d(vector2 coord,
+ float exponent,
+ float jitter,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector2 outPosition)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vector2 offsetF1 = vector2(0.0, 0.0);
+ vector2 positionF1 = vector2(0.0, 0.0);
+ vector2 offsetF2, positionF2;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 pointPosition = cellOffset + hash_01_vector2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor = hash_01_color(cellPosition + offsetF2);
+ outPosition = positionF2 + cellPosition;
+}
+
+void voronoi_distance_to_edge_2d(vector2 coord, float jitter, output float outDistance)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ vector2 vectorToClosest;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 vectorToPoint = cellOffset + hash_01_vector2(cellPosition + cellOffset) * jitter -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 vectorToPoint = cellOffset + hash_01_vector2(cellPosition + cellOffset) * jitter -
+ localPosition;
+ vector2 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ outDistance = minDistance;
+}
+
+void voronoi_n_sphere_radius_2d(vector2 coord, float jitter, output float outRadius)
+{
+ vector2 cellPosition = floor(coord);
+ vector2 localPosition = coord - cellPosition;
+
+ vector2 closestPoint;
+ vector2 closestPointOffset;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector2 cellOffset = vector2(i, j);
+ vector2 pointPosition = cellOffset + hash_01_vector2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vector2 closestPointToClosestPoint;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0)
+ continue;
+ vector2 cellOffset = vector2(i, j) + closestPointOffset;
+ vector2 pointPosition = cellOffset + hash_01_vector2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 3D Voronoi **** */
+
+float voronoi_distance(vector3 a, vector3 b, string metric, float exponent)
+{
+ if (metric == "euclidean")
+ return distance(a, b);
+ else if (metric == "manhattan")
+ return abs(a[0] - b[0]) + abs(a[1] - b[1]) + abs(a[2] - b[2]);
+ else if (metric == "chebychev")
+ return max(abs(a[0] - b[0]), max(abs(a[1] - b[1]), abs(a[2] - b[2])));
+ else if (metric == "minkowski")
+ return pow(pow(abs(a[0] - b[0]), exponent) + pow(abs(a[1] - b[1]), exponent) +
+ pow(abs(a[2] - b[2]), exponent),
+ 1.0 / exponent);
+ else
+ return 0.0;
+}
+
+void voronoi_f1_3d(vector3 coord,
+ float exponent,
+ float jitter,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector3 outPosition)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0;
+ vector3 targetOffset, targetPosition;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 pointPosition = cellOffset + hash_01_vector3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
}
- else if (metric == "manhattan") {
- d = fabs(pd[0]) + fabs(pd[1]) + fabs(pd[2]);
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor = hash_01_color(cellPosition + targetOffset);
+ outPosition = targetPosition + cellPosition;
+}
+
+void voronoi_smooth_f1_3d(vector3 coord,
+ float smoothness,
+ float exponent,
+ float jitter,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector3 outPosition)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ color smoothColor = color(0.0);
+ float smoothDistance = 0.0;
+ vector3 smoothPosition = vector3(0.0);
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 pointPosition = cellOffset + hash_01_vector3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float weight = exp(-smoothness * distanceToPoint);
+ smoothDistance += weight;
+ smoothColor += hash_01_color(cellPosition + cellOffset) * weight;
+ smoothPosition += pointPosition * weight;
+ }
+ }
+ }
+ outDistance = -log(smoothDistance) / smoothness;
+ outColor = smoothColor / smoothDistance;
+ outPosition = cellPosition + smoothPosition / smoothDistance;
+}
+
+void voronoi_f2_3d(vector3 coord,
+ float exponent,
+ float jitter,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector3 outPosition)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vector3 offsetF1 = vector3(0.0);
+ vector3 positionF1 = vector3(0.0);
+ vector3 offsetF2, positionF2;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 pointPosition = cellOffset + hash_01_vector3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
}
- else if (metric == "chebychev") {
- d = max(fabs(pd[0]), max(fabs(pd[1]), fabs(pd[2])));
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
}
- else if (metric == "minkowski") {
- d = pow(pow(fabs(pd[0]), e) + pow(fabs(pd[1]), e) + pow(fabs(pd[2]), e), 1.0 / e);
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor = hash_01_color(cellPosition + offsetF2);
+ outPosition = positionF2 + cellPosition;
+}
+
+void voronoi_distance_to_edge_3d(vector3 coord, float jitter, output float outDistance)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
+
+ vector3 vectorToClosest;
+ float minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 vectorToPoint = cellOffset + hash_01_vector3(cellPosition + cellOffset) * jitter -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
}
+ }
+ }
+ }
- vp += point(xx, yy, zz);
+ minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 vectorToPoint = cellOffset + hash_01_vector3(cellPosition + cellOffset) * jitter -
+ localPosition;
+ vector3 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+}
- if (d < da[0]) {
- da[3] = da[2];
- da[2] = da[1];
- da[1] = da[0];
- da[0] = d;
+void voronoi_n_sphere_radius_3d(vector3 coord, float jitter, output float outRadius)
+{
+ vector3 cellPosition = floor(coord);
+ vector3 localPosition = coord - cellPosition;
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = pa[0];
- pa[0] = vp;
+ vector3 closestPoint;
+ vector3 closestPointOffset;
+ float minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector3 cellOffset = vector3(i, j, k);
+ vector3 pointPosition = cellOffset + hash_01_vector3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
}
- 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;
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vector3 closestPointToClosestPoint;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0)
+ continue;
+ vector3 cellOffset = vector3(i, j, k) + closestPointOffset;
+ vector3 pointPosition = cellOffset + hash_01_vector3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
}
- else if (d < da[2]) {
- da[3] = da[2];
- da[2] = d;
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 4D Voronoi **** */
+
+float voronoi_distance(vector4 a, vector4 b, string metric, float exponent)
+{
+ if (metric == "euclidean")
+ return distance(a, b);
+ else if (metric == "manhattan")
+ return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w);
+ else if (metric == "chebychev")
+ return max(abs(a.x - b.x), max(abs(a.y - b.y), max(abs(a.z - b.z), abs(a.w - b.w))));
+ else if (metric == "minkowski")
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent) +
+ pow(abs(a.z - b.z), exponent) + pow(abs(a.w - b.w), exponent),
+ 1.0 / exponent);
+ else
+ return 0.0;
+}
+
+void voronoi_f1_4d(vector4 coord,
+ float exponent,
+ float jitter,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector4 outPosition)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
- pa[3] = pa[2];
- pa[2] = vp;
+ float minDistance = 8.0;
+ vector4 targetOffset, targetPosition;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 pointPosition = cellOffset + hash_01_vector4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
}
- else if (d < da[3]) {
- da[3] = d;
- pa[3] = vp;
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor = hash_01_color(cellPosition + targetOffset);
+ outPosition = targetPosition + cellPosition;
+}
+
+void voronoi_smooth_f1_4d(vector4 coord,
+ float smoothness,
+ float exponent,
+ float jitter,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector4 outPosition)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
+
+ color smoothColor = color(0.0);
+ float smoothDistance = 0.0;
+ vector4 smoothPosition = vector4(0.0, 0.0, 0.0, 0.0);
+ for (int u = -2; u <= 2; u++) {
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 pointPosition = cellOffset + hash_01_vector4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float weight = exp(-smoothness * distanceToPoint);
+ smoothDistance += weight;
+ smoothColor += hash_01_color(cellPosition + cellOffset) * weight;
+ smoothPosition += pointPosition * weight;
+ }
+ }
+ }
+ }
+ outDistance = -log(smoothDistance) / smoothness;
+ outColor = smoothColor / smoothDistance;
+ outPosition = cellPosition + smoothPosition / smoothDistance;
+}
+
+void voronoi_f2_4d(vector4 coord,
+ float exponent,
+ float jitter,
+ string metric,
+ output float outDistance,
+ output color outColor,
+ output vector4 outPosition)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vector4 offsetF1 = vector4(0.0, 0.0, 0.0, 0.0);
+ vector4 positionF1 = vector4(0.0, 0.0, 0.0, 0.0);
+ vector4 offsetF2, positionF2;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 pointPosition = cellOffset + hash_01_vector4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor = hash_01_color(cellPosition + offsetF2);
+ outPosition = positionF2 + cellPosition;
+}
+
+void voronoi_distance_to_edge_4d(vector4 coord, float jitter, output float outDistance)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
+
+ vector4 vectorToClosest;
+ float minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 vectorToPoint = cellOffset +
+ hash_01_vector4(cellPosition + cellOffset) * jitter -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 vectorToPoint = cellOffset +
+ hash_01_vector4(cellPosition + cellOffset) * jitter -
+ localPosition;
+ vector4 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
}
}
}
}
+ outDistance = minDistance;
}
-/* Voronoi */
+void voronoi_n_sphere_radius_4d(vector4 coord, float jitter, output float outRadius)
+{
+ vector4 cellPosition = floor(coord);
+ vector4 localPosition = coord - cellPosition;
+
+ vector4 closestPoint;
+ vector4 closestPointOffset;
+ float minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vector4 cellOffset = vector4(i, j, k, u);
+ vector4 pointPosition = cellOffset + hash_01_vector4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0;
+ vector4 closestPointToClosestPoint;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0 && u == 0)
+ continue;
+ vector4 cellOffset = vector4(i, j, k, u) + closestPointOffset;
+ vector4 pointPosition = cellOffset + hash_01_vector4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
shader node_voronoi_texture(
int use_mapping = 0,
matrix mapping = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
- string coloring = "intensity",
- string metric = "distance",
- string feature = "F1",
- float Exponent = 1.0,
+ string dimensions = "3D",
+ string feature = "f1",
+ string metric = "euclidean",
+ vector3 Vector = P,
+ float WIn = 0.0,
float Scale = 5.0,
- point Vector = P,
- output float Fac = 0.0,
- output color Color = 0.0)
+ float Smoothness = 5.0,
+ float Exponent = 1.0,
+ float Jitter = 1.0,
+ output float Distance = 0.0,
+ output color Color = 0.0,
+ output vector3 Position = P,
+ output float WOut = 0.0,
+ output float Radius = 0.0)
{
- point p = Vector;
+ float jitter = clamp(Jitter, 0.0, 1.0);
+ float smoothness = max(Smoothness, 1.0);
+ vector3 coord = Vector;
if (use_mapping)
- p = transform(mapping, p);
+ coord = transform(mapping, coord);
- /* compute distance and point coordinate of 4 nearest neighbours */
- float da[4];
- point pa[4];
+ float w = WIn * Scale;
+ coord *= Scale;
- /* compute distance and point coordinate of 4 nearest neighbours */
- voronoi_m(p * Scale, metric, Exponent, da, pa);
-
- if (coloring == "intensity") {
- /* Intensity output */
- if (feature == "F1") {
- Fac = fabs(da[0]);
+ if (dimensions == "1D") {
+ if (feature == "f1") {
+ voronoi_f1_1d(w, Exponent, jitter, metric, Distance, Color, WOut);
+ }
+ else if (feature == "smooth_f1") {
+ voronoi_smooth_f1_1d(w, smoothness, Exponent, jitter, metric, Distance, Color, WOut);
}
- else if (feature == "F2") {
- Fac = fabs(da[1]);
+ else if (feature == "f2") {
+ voronoi_f2_1d(w, Exponent, jitter, metric, Distance, Color, WOut);
}
- else if (feature == "F3") {
- Fac = fabs(da[2]);
+ else if (feature == "distance_to_edge") {
+ voronoi_distance_to_edge_1d(w, jitter, Distance);
}
- else if (feature == "F4") {
- Fac = fabs(da[3]);
+ else if (feature == "n_sphere_radius") {
+ voronoi_n_sphere_radius_1d(w, jitter, Radius);
}
- else if (feature == "F2F1") {
- Fac = fabs(da[1] - da[0]);
+ else {
+ error("Unknown feature!");
}
- Color = color(Fac);
+ WOut = (Scale != 0.0) ? WOut / Scale : 0.0;
}
- else {
- /* Color output */
- if (feature == "F1") {
- Color = pa[0];
+ else if (dimensions == "2D") {
+ vector2 coord2D = vector2(coord[0], coord[1]);
+ vector2 outPosition2D;
+ if (feature == "f1") {
+ voronoi_f1_2d(coord2D, Exponent, jitter, metric, Distance, Color, outPosition2D);
}
- else if (feature == "F2") {
- Color = pa[1];
+ else if (feature == "smooth_f1") {
+ voronoi_smooth_f1_2d(
+ coord2D, smoothness, Exponent, jitter, metric, Distance, Color, outPosition2D);
}
- else if (feature == "F3") {
- Color = pa[2];
+ else if (feature == "f2") {
+ voronoi_f2_2d(coord2D, Exponent, jitter, metric, Distance, Color, outPosition2D);
}
- else if (feature == "F4") {
- Color = pa[3];
+ else if (feature == "distance_to_edge") {
+ voronoi_distance_to_edge_2d(coord2D, jitter, Distance);
}
- else if (feature == "F2F1") {
- Color = fabs(pa[1] - pa[0]);
+ else if (feature == "n_sphere_radius") {
+ voronoi_n_sphere_radius_2d(coord2D, jitter, Radius);
}
-
- Color = cellnoise_color(Color);
- Fac = (Color[0] + Color[1] + Color[2]) * (1.0 / 3.0);
+ else {
+ error("Unknown feature!");
+ }
+ outPosition2D = safe_divide(outPosition2D, Scale);
+ Position = vector3(outPosition2D.x, outPosition2D.y, 0.0);
+ }
+ else if (dimensions == "3D") {
+ if (feature == "f1") {
+ voronoi_f1_3d(coord, Exponent, jitter, metric, Distance, Color, Position);
+ }
+ else if (feature == "smooth_f1") {
+ voronoi_smooth_f1_3d(coord, smoothness, Exponent, jitter, metric, Distance, Color, Position);
+ }
+ else if (feature == "f2") {
+ voronoi_f2_3d(coord, Exponent, jitter, metric, Distance, Color, Position);
+ }
+ else if (feature == "distance_to_edge") {
+ voronoi_distance_to_edge_3d(coord, jitter, Distance);
+ }
+ else if (feature == "n_sphere_radius") {
+ voronoi_n_sphere_radius_3d(coord, jitter, Radius);
+ }
+ else {
+ error("Unknown feature!");
+ }
+ Position = (Scale != 0.0) ? Position / Scale : vector3(0.0);
+ }
+ else if (dimensions == "4D") {
+ vector4 coord4D = vector4(coord[0], coord[1], coord[2], w);
+ vector4 outPosition4D;
+ if (feature == "f1") {
+ voronoi_f1_4d(coord4D, Exponent, jitter, metric, Distance, Color, outPosition4D);
+ }
+ else if (feature == "smooth_f1") {
+ voronoi_smooth_f1_4d(
+ coord4D, smoothness, Exponent, jitter, metric, Distance, Color, outPosition4D);
+ }
+ else if (feature == "f2") {
+ voronoi_f2_4d(coord4D, Exponent, jitter, metric, Distance, Color, outPosition4D);
+ }
+ else if (feature == "distance_to_edge") {
+ voronoi_distance_to_edge_4d(coord4D, jitter, Distance);
+ }
+ else if (feature == "n_sphere_radius") {
+ voronoi_n_sphere_radius_4d(coord4D, jitter, Radius);
+ }
+ else {
+ error("Unknown feature!");
+ }
+ outPosition4D = safe_divide(outPosition4D, Scale);
+ Position = vector3(outPosition4D.x, outPosition4D.y, outPosition4D.z);
+ WOut = outPosition4D.w;
+ }
+ else {
+ error("Unknown dimension!");
}
}
diff --git a/intern/cycles/kernel/shaders/node_wave_texture.osl b/intern/cycles/kernel/shaders/node_wave_texture.osl
index dfc2dbfb800..ec0c9b948fc 100644
--- a/intern/cycles/kernel/shaders/node_wave_texture.osl
+++ b/intern/cycles/kernel/shaders/node_wave_texture.osl
@@ -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 * noise_turbulence(p * dscale, detail));
}
if (profile == "sine") {
diff --git a/intern/cycles/kernel/shaders/node_white_noise_texture.osl b/intern/cycles/kernel/shaders/node_white_noise_texture.osl
new file mode 100644
index 00000000000..19a7cd9191e
--- /dev/null
+++ b/intern/cycles/kernel/shaders/node_white_noise_texture.osl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011-2013 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stdosl.h"
+
+shader node_white_noise_texture(string dimensions = "3D",
+ point Vector = vector(0.0, 0.0, 0.0),
+ float W = 0.0,
+ output float Value = 0.0)
+{
+ if (dimensions == "1D") {
+ Value = noise("hash", W);
+ }
+ else if (dimensions == "2D") {
+ Value = noise("hash", Vector[0], Vector[1]);
+ }
+ else if (dimensions == "3D") {
+ Value = noise("hash", Vector);
+ }
+ else if (dimensions == "4D") {
+ Value = noise("hash", Vector, W);
+ }
+ else {
+ warning("%s", "Unknown dimension!");
+ }
+}
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 4a386afa5de..6c32f109bab 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -153,6 +153,7 @@ CCL_NAMESPACE_END
#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"
@@ -192,6 +193,10 @@ CCL_NAMESPACE_END
#include "kernel/svm/svm_vector_transform.h"
#include "kernel/svm/svm_voxel.h"
#include "kernel/svm/svm_bump.h"
+#include "kernel/svm/svm_map_range.h"
+#include "kernel/svm/svm_clamp.h"
+#include "kernel/svm/svm_white_noise.h"
+#include "kernel/svm/svm_vertex_color.h"
#ifdef __SHADER_RAYTRACE__
# include "kernel/svm/svm_ao.h"
@@ -276,6 +281,9 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
case NODE_ATTR:
svm_node_attr(kg, sd, stack, node);
break;
+ case NODE_VERTEX_COLOR:
+ svm_node_vertex_color(kg, sd, stack, node.y, node.z, node.w);
+ break;
# if NODES_FEATURE(NODE_FEATURE_BUMP)
case NODE_GEOMETRY_BUMP_DX:
svm_node_geometry_bump_dx(kg, sd, stack, node.y, node.z);
@@ -301,7 +309,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__
@@ -315,6 +323,12 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
case NODE_ATTR_BUMP_DY:
svm_node_attr_bump_dy(kg, sd, stack, node);
break;
+ case NODE_VERTEX_COLOR_BUMP_DX:
+ svm_node_vertex_color_bump_dx(kg, sd, stack, node.y, node.z, node.w);
+ break;
+ case NODE_VERTEX_COLOR_BUMP_DY:
+ svm_node_vertex_color_bump_dy(kg, sd, stack, node.y, node.z, node.w);
+ break;
case NODE_TEX_COORD_BUMP_DX:
svm_node_tex_coord_bump_dx(kg, sd, path_flag, stack, node, &offset);
break;
@@ -393,8 +407,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);
@@ -413,10 +430,10 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
svm_node_tex_gradient(sd, stack, node);
break;
case NODE_TEX_VORONOI:
- svm_node_tex_voronoi(kg, sd, stack, node, &offset);
+ svm_node_tex_voronoi(kg, sd, stack, node.y, node.z, node.w, &offset);
break;
case NODE_TEX_MUSGRAVE:
- svm_node_tex_musgrave(kg, sd, stack, node, &offset);
+ svm_node_tex_musgrave(kg, sd, stack, node.y, node.z, node.w, &offset);
break;
case NODE_TEX_WAVE:
svm_node_tex_wave(kg, sd, stack, node, &offset);
@@ -430,6 +447,9 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
case NODE_TEX_BRICK:
svm_node_tex_brick(kg, sd, stack, node, &offset);
break;
+ case NODE_TEX_WHITE_NOISE:
+ svm_node_tex_white_noise(kg, sd, stack, node.y, node.z, node.w, &offset);
+ break;
# endif /* __TEXTURES__ */
# ifdef __EXTRA_NODES__
case NODE_NORMAL:
@@ -486,6 +506,12 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg,
case NODE_BLACKBODY:
svm_node_blackbody(kg, sd, stack, node.y, node.z);
break;
+ case NODE_MAP_RANGE:
+ svm_node_map_range(kg, sd, stack, node.y, node.z, node.w, &offset);
+ break;
+ case NODE_CLAMP:
+ svm_node_clamp(kg, sd, stack, node.y, node.z, node.w, &offset);
+ break;
# endif /* __EXTRA_NODES__ */
# if NODES_FEATURE(NODE_FEATURE_VOLUME)
case NODE_TEX_VOXEL:
diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h
index a67cfe91a30..84e17fabd62 100644
--- a/intern/cycles/kernel/svm/svm_attribute.h
+++ b/intern/cycles/kernel/svm/svm_attribute.h
@@ -69,6 +69,15 @@ ccl_device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, u
stack_store_float3(stack, out_offset, make_float3(f.x, f.y, 0.0f));
}
}
+ else if (desc.type == NODE_ATTR_RGBA) {
+ float4 f = primitive_attribute_float4(kg, sd, desc, NULL, NULL);
+ if (type == NODE_ATTR_FLOAT) {
+ stack_store_float(stack, out_offset, average_float4(f));
+ }
+ else {
+ stack_store_float3(stack, out_offset, float4_to_float3(f));
+ }
+ }
else {
float3 f = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
if (type == NODE_ATTR_FLOAT) {
@@ -113,6 +122,16 @@ ccl_device_noinline
stack_store_float3(stack, out_offset, make_float3(f.x + dx.x, f.y + dx.y, 0.0f));
}
}
+ else if (desc.type == NODE_ATTR_RGBA) {
+ float4 dx;
+ float4 f = primitive_attribute_float4(kg, sd, desc, &dx, NULL);
+ if (type == NODE_ATTR_FLOAT) {
+ stack_store_float(stack, out_offset, average_float4(f + dx));
+ }
+ else {
+ stack_store_float3(stack, out_offset, float4_to_float3(f + dx));
+ }
+ }
else {
float3 dx;
float3 f = primitive_surface_attribute_float3(kg, sd, desc, &dx, NULL);
@@ -158,6 +177,16 @@ ccl_device_noinline
stack_store_float3(stack, out_offset, make_float3(f.x + dy.x, f.y + dy.y, 0.0f));
}
}
+ else if (desc.type == NODE_ATTR_RGBA) {
+ float4 dy;
+ float4 f = primitive_attribute_float4(kg, sd, desc, NULL, &dy);
+ if (type == NODE_ATTR_FLOAT) {
+ stack_store_float(stack, out_offset, average_float4(f + dy));
+ }
+ else {
+ stack_store_float3(stack, out_offset, float4_to_float3(f + dy));
+ }
+ }
else {
float3 dy;
float3 f = primitive_surface_attribute_float3(kg, sd, desc, NULL, &dy);
diff --git a/intern/cycles/kernel/svm/svm_clamp.h b/intern/cycles/kernel/svm/svm_clamp.h
new file mode 100644
index 00000000000..f32a05f7817
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_clamp.h
@@ -0,0 +1,38 @@
+/*
+ * 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
+
+/* Clamp Node */
+
+ccl_device void svm_node_clamp(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint value_offset,
+ uint min_offset,
+ uint max_offset,
+ int *offset)
+{
+ uint4 node1 = read_node(kg, offset);
+
+ float value = stack_load_float(stack, value_offset);
+ float min = stack_load_float(stack, min_offset);
+ float max = stack_load_float(stack, max_offset);
+
+ stack_store_float(stack, node1.y, clamp(value, min, max));
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h
index a9104643299..5db4f24fbed 100644
--- a/intern/cycles/kernel/svm/svm_geometry.h
+++ b/intern/cycles/kernel/svm/svm_geometry.h
@@ -113,6 +113,10 @@ ccl_device void svm_node_object_info(
stack_store_float3(stack, out_offset, object_location(kg, sd));
return;
}
+ case NODE_INFO_OB_COLOR: {
+ stack_store_float3(stack, out_offset, object_color(kg, sd->object));
+ return;
+ }
case NODE_INFO_OB_INDEX:
data = object_pass_id(kg, sd->object);
break;
@@ -149,7 +153,7 @@ ccl_device void svm_node_particle_info(
}
case NODE_INFO_PAR_RANDOM: {
int particle_id = object_particle_id(kg, sd->object);
- float random = hash_int_01(particle_index(kg, particle_id));
+ float random = hash_uint_to_float(particle_index(kg, particle_id));
stack_store_float(stack, out_offset, random);
break;
}
diff --git a/intern/cycles/kernel/svm/svm_map_range.h b/intern/cycles/kernel/svm/svm_map_range.h
new file mode 100644
index 00000000000..973a4badc45
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_map_range.h
@@ -0,0 +1,47 @@
+/*
+ * 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
+
+/* Map Range Node */
+
+ccl_device void svm_node_map_range(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint value_offset,
+ uint fromMin_offset,
+ uint fromMax_offset,
+ int *offset)
+{
+ uint4 node1 = read_node(kg, offset);
+
+ float value = stack_load_float(stack, value_offset);
+ float fromMin = stack_load_float(stack, fromMin_offset);
+ float fromMax = stack_load_float(stack, fromMax_offset);
+ float toMin = stack_load_float(stack, node1.y);
+ float toMax = stack_load_float(stack, node1.z);
+
+ float result;
+ if (fromMax != fromMin) {
+ result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
+ }
+ else {
+ result = 0.0f;
+ }
+ stack_store_float(stack, node1.w, result);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_mapping.h b/intern/cycles/kernel/svm/svm_mapping.h
index 998a29912d4..997b09fe82f 100644
--- a/intern/cycles/kernel/svm/svm_mapping.h
+++ b/intern/cycles/kernel/svm/svm_mapping.h
@@ -18,7 +18,28 @@ 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 vector_offset,
+ uint location_offset,
+ int *offset)
+{
+ uint4 node1 = read_node(kg, offset);
+
+ float3 vector = stack_load_float3(stack, vector_offset);
+ float3 location = stack_load_float3(stack, location_offset);
+ float3 rotation = stack_load_float3(stack, node1.y);
+ float3 scale = stack_load_float3(stack, node1.z);
+
+ float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale);
+ stack_store_float3(stack, node1.w, 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..a278a2a5c2a
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_mapping_util.h
@@ -0,0 +1,46 @@
+/*
+ * 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;
+ if (type == NODE_MAPPING_TYPE_TEXTURE) {
+ rotationTransform = euler_to_transform(-rotation);
+ }
+ else {
+ 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(&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_math.h b/intern/cycles/kernel/svm/svm_math.h
index 5920913825b..e570f1840af 100644
--- a/intern/cycles/kernel/svm/svm_math.h
+++ b/intern/cycles/kernel/svm/svm_math.h
@@ -21,15 +21,14 @@ CCL_NAMESPACE_BEGIN
ccl_device void svm_node_math(KernelGlobals *kg,
ShaderData *sd,
float *stack,
- uint itype,
- uint f1_offset,
- uint f2_offset,
+ uint type,
+ uint a_offset,
+ uint b_offset,
int *offset)
{
- NodeMath type = (NodeMath)itype;
- float f1 = stack_load_float(stack, f1_offset);
- float f2 = stack_load_float(stack, f2_offset);
- float f = svm_math(type, f1, f2);
+ float a = stack_load_float(stack, a_offset);
+ float b = stack_load_float(stack, b_offset);
+ float f = svm_math((NodeMathType)type, a, b);
uint4 node1 = read_node(kg, offset);
@@ -39,25 +38,24 @@ ccl_device void svm_node_math(KernelGlobals *kg,
ccl_device void svm_node_vector_math(KernelGlobals *kg,
ShaderData *sd,
float *stack,
- uint itype,
- uint v1_offset,
- uint v2_offset,
+ uint type,
+ uint a_offset,
+ uint b_offset,
int *offset)
{
- NodeVectorMath type = (NodeVectorMath)itype;
- float3 v1 = stack_load_float3(stack, v1_offset);
- float3 v2 = stack_load_float3(stack, v2_offset);
+ uint4 node1 = read_node(kg, offset);
+ float3 a = stack_load_float3(stack, a_offset);
+ float3 b = stack_load_float3(stack, b_offset);
+ float scale = stack_load_float(stack, node1.y);
+
float f;
float3 v;
+ svm_vector_math(&f, &v, (NodeVectorMathType)type, a, b, scale);
- svm_vector_math(&f, &v, type, v1, v2);
-
- uint4 node1 = read_node(kg, offset);
-
- if (stack_valid(node1.y))
- stack_store_float(stack, node1.y, f);
if (stack_valid(node1.z))
- stack_store_float3(stack, node1.z, v);
+ stack_store_float(stack, node1.z, f);
+ if (stack_valid(node1.w))
+ stack_store_float3(stack, node1.w, v);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_math_util.h b/intern/cycles/kernel/svm/svm_math_util.h
index e3544515f1b..6661691938a 100644
--- a/intern/cycles/kernel/svm/svm_math_util.h
+++ b/intern/cycles/kernel/svm/svm_math_util.h
@@ -16,99 +16,132 @@
CCL_NAMESPACE_BEGIN
-ccl_device float average_fac(float3 v)
-{
- return (fabsf(v.x) + fabsf(v.y) + fabsf(v.z)) / 3.0f;
-}
-
ccl_device void svm_vector_math(
- float *Fac, float3 *Vector, NodeVectorMath type, float3 Vector1, float3 Vector2)
+ float *value, float3 *vector, NodeVectorMathType type, float3 a, float3 b, float scale)
{
- if (type == NODE_VECTOR_MATH_ADD) {
- *Vector = Vector1 + Vector2;
- *Fac = average_fac(*Vector);
- }
- else if (type == NODE_VECTOR_MATH_SUBTRACT) {
- *Vector = Vector1 - Vector2;
- *Fac = average_fac(*Vector);
- }
- else if (type == NODE_VECTOR_MATH_AVERAGE) {
- *Vector = safe_normalize_len(Vector1 + Vector2, Fac);
- }
- else if (type == NODE_VECTOR_MATH_DOT_PRODUCT) {
- *Fac = dot(Vector1, Vector2);
- *Vector = make_float3(0.0f, 0.0f, 0.0f);
- }
- else if (type == NODE_VECTOR_MATH_CROSS_PRODUCT) {
- *Vector = safe_normalize_len(cross(Vector1, Vector2), Fac);
- }
- else if (type == NODE_VECTOR_MATH_NORMALIZE) {
- *Vector = safe_normalize_len(Vector1, Fac);
- }
- else {
- *Fac = 0.0f;
- *Vector = make_float3(0.0f, 0.0f, 0.0f);
+ switch (type) {
+ case NODE_VECTOR_MATH_ADD:
+ *vector = a + b;
+ break;
+ case NODE_VECTOR_MATH_SUBTRACT:
+ *vector = a - b;
+ break;
+ case NODE_VECTOR_MATH_MULTIPLY:
+ *vector = a * b;
+ break;
+ case NODE_VECTOR_MATH_DIVIDE:
+ *vector = safe_divide_float3_float3(a, b);
+ break;
+ case NODE_VECTOR_MATH_CROSS_PRODUCT:
+ *vector = cross(a, b);
+ break;
+ case NODE_VECTOR_MATH_PROJECT:
+ *vector = project(a, b);
+ break;
+ case NODE_VECTOR_MATH_REFLECT:
+ *vector = reflect(a, b);
+ break;
+ case NODE_VECTOR_MATH_DOT_PRODUCT:
+ *value = dot(a, b);
+ break;
+ case NODE_VECTOR_MATH_DISTANCE:
+ *value = len(a - b);
+ break;
+ case NODE_VECTOR_MATH_LENGTH:
+ *value = len(a);
+ break;
+ case NODE_VECTOR_MATH_SCALE:
+ *vector = a * scale;
+ break;
+ case NODE_VECTOR_MATH_NORMALIZE:
+ *vector = safe_normalize(a);
+ break;
+ case NODE_VECTOR_MATH_SNAP:
+ *vector = make_float3(floorf(safe_divide(a.x, b.x)) * b.x,
+ floorf(safe_divide(a.y, b.y)) * b.y,
+ floorf(safe_divide(a.z, b.z)) * b.z);
+ break;
+ case NODE_VECTOR_MATH_FLOOR:
+ *vector = floor(a);
+ break;
+ case NODE_VECTOR_MATH_CEIL:
+ *vector = ceil(a);
+ break;
+ case NODE_VECTOR_MATH_MODULO:
+ *vector = make_float3(safe_modulo(a.x, b.x), safe_modulo(a.y, b.y), safe_modulo(a.z, b.z));
+ break;
+ case NODE_VECTOR_MATH_FRACTION:
+ *vector = fract(a);
+ break;
+ case NODE_VECTOR_MATH_ABSOLUTE:
+ *vector = fabs(a);
+ break;
+ case NODE_VECTOR_MATH_MINIMUM:
+ *vector = min(a, b);
+ break;
+ case NODE_VECTOR_MATH_MAXIMUM:
+ *vector = max(a, b);
+ break;
+ default:
+ *vector = make_float3(0.0f, 0.0f, 0.0f);
+ *value = 0.0f;
}
}
-ccl_device float svm_math(NodeMath type, float Fac1, float Fac2)
+ccl_device float svm_math(NodeMathType type, float a, float b)
{
- float Fac;
-
- if (type == NODE_MATH_ADD)
- Fac = Fac1 + Fac2;
- else if (type == NODE_MATH_SUBTRACT)
- Fac = Fac1 - Fac2;
- else if (type == NODE_MATH_MULTIPLY)
- Fac = Fac1 * Fac2;
- else if (type == NODE_MATH_DIVIDE)
- Fac = safe_divide(Fac1, Fac2);
- else if (type == NODE_MATH_SINE)
- Fac = sinf(Fac1);
- else if (type == NODE_MATH_COSINE)
- Fac = cosf(Fac1);
- else if (type == NODE_MATH_TANGENT)
- Fac = tanf(Fac1);
- else if (type == NODE_MATH_ARCSINE)
- Fac = safe_asinf(Fac1);
- else if (type == NODE_MATH_ARCCOSINE)
- Fac = safe_acosf(Fac1);
- else if (type == NODE_MATH_ARCTANGENT)
- Fac = atanf(Fac1);
- else if (type == NODE_MATH_POWER)
- Fac = safe_powf(Fac1, Fac2);
- else if (type == NODE_MATH_LOGARITHM)
- Fac = safe_logf(Fac1, Fac2);
- else if (type == NODE_MATH_MINIMUM)
- Fac = fminf(Fac1, Fac2);
- else if (type == NODE_MATH_MAXIMUM)
- Fac = fmaxf(Fac1, Fac2);
- else if (type == NODE_MATH_ROUND)
- Fac = floorf(Fac1 + 0.5f);
- else if (type == NODE_MATH_LESS_THAN)
- Fac = Fac1 < Fac2;
- else if (type == NODE_MATH_GREATER_THAN)
- Fac = Fac1 > Fac2;
- else if (type == NODE_MATH_MODULO)
- Fac = safe_modulo(Fac1, Fac2);
- else if (type == NODE_MATH_ABSOLUTE)
- Fac = fabsf(Fac1);
- else if (type == NODE_MATH_ARCTAN2)
- Fac = atan2f(Fac1, Fac2);
- else if (type == NODE_MATH_FLOOR)
- Fac = floorf(Fac1);
- else if (type == NODE_MATH_CEIL)
- Fac = ceilf(Fac1);
- else if (type == NODE_MATH_FRACT)
- Fac = Fac1 - floorf(Fac1);
- else if (type == NODE_MATH_SQRT)
- Fac = safe_sqrtf(Fac1);
- else if (type == NODE_MATH_CLAMP)
- Fac = saturate(Fac1);
- else
- Fac = 0.0f;
-
- return Fac;
+ switch (type) {
+ case NODE_MATH_ADD:
+ return a + b;
+ case NODE_MATH_SUBTRACT:
+ return a - b;
+ case NODE_MATH_MULTIPLY:
+ return a * b;
+ case NODE_MATH_DIVIDE:
+ return safe_divide(a, b);
+ case NODE_MATH_POWER:
+ return safe_powf(a, b);
+ case NODE_MATH_LOGARITHM:
+ return safe_logf(a, b);
+ case NODE_MATH_SQRT:
+ return safe_sqrtf(a);
+ case NODE_MATH_ABSOLUTE:
+ return fabsf(a);
+ case NODE_MATH_MINIMUM:
+ return fminf(a, b);
+ case NODE_MATH_MAXIMUM:
+ return fmaxf(a, b);
+ case NODE_MATH_LESS_THAN:
+ return a < b;
+ case NODE_MATH_GREATER_THAN:
+ return a > b;
+ case NODE_MATH_ROUND:
+ return floorf(a + 0.5f);
+ case NODE_MATH_FLOOR:
+ return floorf(a);
+ case NODE_MATH_CEIL:
+ return ceilf(a);
+ case NODE_MATH_FRACTION:
+ return a - floorf(a);
+ case NODE_MATH_MODULO:
+ return safe_modulo(a, b);
+ case NODE_MATH_SINE:
+ return sinf(a);
+ case NODE_MATH_COSINE:
+ return cosf(a);
+ case NODE_MATH_TANGENT:
+ return tanf(a);
+ case NODE_MATH_ARCSINE:
+ return safe_asinf(a);
+ case NODE_MATH_ARCCOSINE:
+ return safe_acosf(a);
+ case NODE_MATH_ARCTANGENT:
+ return atanf(a);
+ case NODE_MATH_ARCTAN2:
+ return atan2f(a, b);
+ default:
+ return 0.0f;
+ }
}
/* Calculate color in range 800..12000 using an approximation
diff --git a/intern/cycles/kernel/svm/svm_musgrave.h b/intern/cycles/kernel/svm/svm_musgrave.h
index 67fb5ca6241..e0d04cc7d84 100644
--- a/intern/cycles/kernel/svm/svm_musgrave.h
+++ b/intern/cycles/kernel/svm/svm_musgrave.h
@@ -16,7 +16,7 @@
CCL_NAMESPACE_BEGIN
-/* Musgrave fBm
+/* 1D Musgrave fBm
*
* H: fractal increment parameter
* lacunarity: gap between successive frequencies
@@ -25,59 +25,227 @@ CCL_NAMESPACE_BEGIN
* from "Texturing and Modelling: A procedural approach"
*/
-ccl_device_noinline float noise_musgrave_fBm(float3 p, float H, float lacunarity, float octaves)
+ccl_device_noinline float noise_musgrave_fBm_1d(float p, float H, float lacunarity, float octaves)
{
float rmd;
float value = 0.0f;
float pwr = 1.0f;
float pwHL = powf(lacunarity, -H);
- int i;
- for (i = 0; i < float_to_int(octaves); i++) {
- value += snoise(p) * pwr;
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value += snoise_1d(p) * pwr;
pwr *= pwHL;
p *= lacunarity;
}
rmd = octaves - floorf(octaves);
- if (rmd != 0.0f)
- value += rmd * snoise(p) * pwr;
+ if (rmd != 0.0f) {
+ value += rmd * snoise_1d(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 1D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+ccl_device_noinline float noise_musgrave_multi_fractal_1d(float p,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float rmd;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value *= (pwr * snoise_1d(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * snoise_1d(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+/* 1D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline float noise_musgrave_hetero_terrain_1d(
+ float p, float H, float lacunarity, float octaves, float offset)
+{
+ float value, increment, rmd;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + snoise_1d(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ increment = (snoise_1d(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ increment = (snoise_1d(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 1D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline float noise_musgrave_hybrid_multi_fractal_1d(
+ float p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight, rmd;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ result = snoise_1d(p) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ signal = (snoise_1d(p) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ result += rmd * ((snoise_1d(p) + offset) * pwr);
+ }
+
+ return result;
+}
+
+/* 1D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline float noise_musgrave_ridged_multi_fractal_1d(
+ float p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ signal = offset - fabsf(snoise_1d(p));
+ signal *= signal;
+ result = signal;
+ weight = 1.0f;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ p *= lacunarity;
+ weight = saturate(signal * gain);
+ signal = offset - fabsf(snoise_1d(p));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return result;
+}
+
+/* 2D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+ccl_device_noinline float noise_musgrave_fBm_2d(float2 p, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value += snoise_2d(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * snoise_2d(p) * pwr;
+ }
return value;
}
-/* Musgrave Multifractal
+/* 2D Musgrave Multifractal
*
* H: highest fractal dimension
* lacunarity: gap between successive frequencies
* octaves: number of frequencies in the fBm
*/
-ccl_device_noinline float noise_musgrave_multi_fractal(float3 p,
- float H,
- float lacunarity,
- float octaves)
+ccl_device_noinline float noise_musgrave_multi_fractal_2d(float2 p,
+ float H,
+ float lacunarity,
+ float octaves)
{
float rmd;
float value = 1.0f;
float pwr = 1.0f;
float pwHL = powf(lacunarity, -H);
- int i;
- for (i = 0; i < float_to_int(octaves); i++) {
- value *= (pwr * snoise(p) + 1.0f);
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value *= (pwr * snoise_2d(p) + 1.0f);
pwr *= pwHL;
p *= lacunarity;
}
rmd = octaves - floorf(octaves);
- if (rmd != 0.0f)
- value *= (rmd * pwr * snoise(p) + 1.0f); /* correct? */
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * snoise_2d(p) + 1.0f); /* correct? */
+ }
return value;
}
-/* Musgrave Heterogeneous Terrain
+/* 2D Musgrave Heterogeneous Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -85,20 +253,187 @@ ccl_device_noinline float noise_musgrave_multi_fractal(float3 p,
* offset: raises the terrain from `sea level'
*/
-ccl_device_noinline float noise_musgrave_hetero_terrain(
+ccl_device_noinline float noise_musgrave_hetero_terrain_2d(
+ float2 p, float H, float lacunarity, float octaves, float offset)
+{
+ float value, increment, rmd;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + snoise_2d(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ increment = (snoise_2d(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ increment = (snoise_2d(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 2D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline float noise_musgrave_hybrid_multi_fractal_2d(
+ float2 p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight, rmd;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ result = snoise_2d(p) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ signal = (snoise_2d(p) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ result += rmd * ((snoise_2d(p) + offset) * pwr);
+ }
+
+ return result;
+}
+
+/* 2D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline float noise_musgrave_ridged_multi_fractal_2d(
+ float2 p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ signal = offset - fabsf(snoise_2d(p));
+ signal *= signal;
+ result = signal;
+ weight = 1.0f;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ p *= lacunarity;
+ weight = saturate(signal * gain);
+ signal = offset - fabsf(snoise_2d(p));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return result;
+}
+
+/* 3D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+ccl_device_noinline float noise_musgrave_fBm_3d(float3 p, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value += snoise_3d(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * snoise_3d(p) * pwr;
+ }
+
+ return value;
+}
+
+/* 3D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+ccl_device_noinline float noise_musgrave_multi_fractal_3d(float3 p,
+ float H,
+ float lacunarity,
+ float octaves)
+{
+ float rmd;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value *= (pwr * snoise_3d(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * snoise_3d(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+/* 3D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline float noise_musgrave_hetero_terrain_3d(
float3 p, float H, float lacunarity, float octaves, float offset)
{
float value, increment, rmd;
float pwHL = powf(lacunarity, -H);
float pwr = pwHL;
- 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;
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ increment = (snoise_3d(p) + offset) * pwr * value;
value += increment;
pwr *= pwHL;
p *= lacunarity;
@@ -106,14 +441,14 @@ ccl_device_noinline 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;
}
return value;
}
-/* Hybrid Additive/Multiplicative Multifractal Terrain
+/* 3D Hybrid Additive/Multiplicative Multifractal Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -121,23 +456,23 @@ ccl_device_noinline float noise_musgrave_hetero_terrain(
* offset: raises the terrain from `sea level'
*/
-ccl_device_noinline float noise_musgrave_hybrid_multi_fractal(
+ccl_device_noinline float noise_musgrave_hybrid_multi_fractal_3d(
float3 p, float H, float lacunarity, float octaves, float offset, float gain)
{
float result, signal, weight, rmd;
float pwHL = powf(lacunarity, -H);
float pwr = pwHL;
- int i;
- result = snoise(p) + offset;
+ result = snoise_3d(p) + offset;
weight = gain * result;
p *= lacunarity;
- for (i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
- if (weight > 1.0f)
+ for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
+ 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;
@@ -145,13 +480,14 @@ ccl_device_noinline float noise_musgrave_hybrid_multi_fractal(
}
rmd = octaves - floorf(octaves);
- if (rmd != 0.0f)
- result += rmd * ((snoise(p) + offset) * pwr);
+ if (rmd != 0.0f) {
+ result += rmd * ((snoise_3d(p) + offset) * pwr);
+ }
return result;
}
-/* Ridged Multifractal Terrain
+/* 3D Ridged Multifractal Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -159,23 +495,22 @@ ccl_device_noinline float noise_musgrave_hybrid_multi_fractal(
* offset: raises the terrain from `sea level'
*/
-ccl_device_noinline float noise_musgrave_ridged_multi_fractal(
+ccl_device_noinline float noise_musgrave_ridged_multi_fractal_3d(
float3 p, float H, float lacunarity, float octaves, float offset, float gain)
{
float result, signal, weight;
float pwHL = powf(lacunarity, -H);
float pwr = pwHL;
- int i;
- signal = offset - fabsf(snoise(p));
+ signal = offset - fabsf(snoise_3d(p));
signal *= signal;
result = signal;
weight = 1.0f;
- for (i = 1; i < float_to_int(octaves); i++) {
+ for (int 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;
@@ -185,67 +520,316 @@ ccl_device_noinline float noise_musgrave_ridged_multi_fractal(
return result;
}
-/* Shader */
+/* 4D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
-ccl_device float svm_musgrave(NodeMusgraveType type,
- float dimension,
- float lacunarity,
- float octaves,
- float offset,
- float intensity,
- float gain,
- float3 p)
+ccl_device_noinline float noise_musgrave_fBm_4d(float4 p, float H, float lacunarity, float octaves)
{
- if (type == NODE_MUSGRAVE_MULTIFRACTAL)
- return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
- else if (type == NODE_MUSGRAVE_FBM)
- return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
- else if (type == NODE_MUSGRAVE_HYBRID_MULTIFRACTAL)
- return intensity *
- noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
- else if (type == NODE_MUSGRAVE_RIDGED_MULTIFRACTAL)
- return intensity *
- noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
- else if (type == NODE_MUSGRAVE_HETERO_TERRAIN)
- return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
+ float rmd;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
+
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value += snoise_4d(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value += rmd * snoise_4d(p) * pwr;
+ }
- return 0.0f;
+ return value;
}
-ccl_device void svm_node_tex_musgrave(
- KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+/* 4D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+ccl_device_noinline float noise_musgrave_multi_fractal_4d(float4 p,
+ float H,
+ float lacunarity,
+ float octaves)
{
- uint4 node2 = read_node(kg, offset);
- uint4 node3 = read_node(kg, offset);
+ float rmd;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ float pwHL = powf(lacunarity, -H);
- uint type, co_offset, color_offset, fac_offset;
- uint dimension_offset, lacunarity_offset, detail_offset, offset_offset;
- uint gain_offset, scale_offset;
+ for (int i = 0; i < float_to_int(octaves); i++) {
+ value *= (pwr * snoise_4d(p) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ value *= (rmd * pwr * snoise_4d(p) + 1.0f); /* correct? */
+ }
+
+ return value;
+}
+
+/* 4D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline float noise_musgrave_hetero_terrain_4d(
+ float4 p, float H, float lacunarity, float octaves, float offset)
+{
+ float value, increment, rmd;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + snoise_4d(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ increment = (snoise_4d(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ increment = (snoise_4d(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* 4D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline float noise_musgrave_hybrid_multi_fractal_4d(
+ float4 p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight, rmd;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
- decode_node_uchar4(node.y, &type, &co_offset, &color_offset, &fac_offset);
+ result = snoise_4d(p) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < float_to_int(octaves)); i++) {
+ if (weight > 1.0f) {
+ weight = 1.0f;
+ }
+
+ signal = (snoise_4d(p) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floorf(octaves);
+ if (rmd != 0.0f) {
+ result += rmd * ((snoise_4d(p) + offset) * pwr);
+ }
+
+ return result;
+}
+
+/* 4D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+ccl_device_noinline float noise_musgrave_ridged_multi_fractal_4d(
+ float4 p, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight;
+ float pwHL = powf(lacunarity, -H);
+ float pwr = pwHL;
+
+ signal = offset - fabsf(snoise_4d(p));
+ signal *= signal;
+ result = signal;
+ weight = 1.0f;
+
+ for (int i = 1; i < float_to_int(octaves); i++) {
+ p *= lacunarity;
+ weight = saturate(signal * gain);
+ signal = offset - fabsf(snoise_4d(p));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return result;
+}
+
+ccl_device void svm_node_tex_musgrave(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint offsets1,
+ uint offsets2,
+ uint offsets3,
+ int *offset)
+{
+ uint type, dimensions, co_offset, w_offset;
+ uint scale_offset, detail_offset, dimension_offset, lacunarity_offset;
+ uint offset_offset, gain_offset, fac_offset;
+
+ decode_node_uchar4(offsets1, &type, &dimensions, &co_offset, &w_offset);
decode_node_uchar4(
- node.z, &dimension_offset, &lacunarity_offset, &detail_offset, &offset_offset);
- decode_node_uchar4(node.w, &gain_offset, &scale_offset, NULL, NULL);
+ offsets2, &scale_offset, &detail_offset, &dimension_offset, &lacunarity_offset);
+ decode_node_uchar4(offsets3, &offset_offset, &gain_offset, &fac_offset, NULL);
+
+ uint4 node1 = read_node(kg, offset);
+ uint4 node2 = read_node(kg, offset);
float3 co = stack_load_float3(stack, co_offset);
- float dimension = stack_load_float_default(stack, dimension_offset, node2.x);
- float lacunarity = stack_load_float_default(stack, lacunarity_offset, node2.y);
- float detail = stack_load_float_default(stack, detail_offset, node2.z);
- float foffset = stack_load_float_default(stack, offset_offset, node2.w);
- float gain = stack_load_float_default(stack, gain_offset, node3.x);
- float scale = stack_load_float_default(stack, scale_offset, node3.y);
+ float w = stack_load_float_default(stack, w_offset, node1.x);
+ float scale = stack_load_float_default(stack, scale_offset, node1.y);
+ float detail = stack_load_float_default(stack, detail_offset, node1.z);
+ float dimension = stack_load_float_default(stack, dimension_offset, node1.w);
+ float lacunarity = stack_load_float_default(stack, lacunarity_offset, node2.x);
+ float foffset = stack_load_float_default(stack, offset_offset, node2.y);
+ float gain = stack_load_float_default(stack, gain_offset, node2.z);
dimension = fmaxf(dimension, 1e-5f);
detail = clamp(detail, 0.0f, 16.0f);
lacunarity = fmaxf(lacunarity, 1e-5f);
- float f = svm_musgrave(
- (NodeMusgraveType)type, dimension, lacunarity, detail, foffset, 1.0f, gain, co * scale);
+ float fac;
+
+ switch (dimensions) {
+ case 1: {
+ float p = w * scale;
+ switch ((NodeMusgraveType)type) {
+ case NODE_MUSGRAVE_MULTIFRACTAL:
+ fac = noise_musgrave_multi_fractal_1d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_FBM:
+ fac = noise_musgrave_fBm_1d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
+ fac = noise_musgrave_hybrid_multi_fractal_1d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
+ fac = noise_musgrave_ridged_multi_fractal_1d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_HETERO_TERRAIN:
+ fac = noise_musgrave_hetero_terrain_1d(p, dimension, lacunarity, detail, foffset);
+ break;
+ default:
+ fac = 0.0f;
+ }
+ break;
+ }
+ case 2: {
+ float2 p = make_float2(co.x, co.y) * scale;
+ switch ((NodeMusgraveType)type) {
+ case NODE_MUSGRAVE_MULTIFRACTAL:
+ fac = noise_musgrave_multi_fractal_2d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_FBM:
+ fac = noise_musgrave_fBm_2d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
+ fac = noise_musgrave_hybrid_multi_fractal_2d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
+ fac = noise_musgrave_ridged_multi_fractal_2d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_HETERO_TERRAIN:
+ fac = noise_musgrave_hetero_terrain_2d(p, dimension, lacunarity, detail, foffset);
+ break;
+ default:
+ fac = 0.0f;
+ }
+ break;
+ }
+ case 3: {
+ float3 p = co * scale;
+ switch ((NodeMusgraveType)type) {
+ case NODE_MUSGRAVE_MULTIFRACTAL:
+ fac = noise_musgrave_multi_fractal_3d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_FBM:
+ fac = noise_musgrave_fBm_3d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
+ fac = noise_musgrave_hybrid_multi_fractal_3d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
+ fac = noise_musgrave_ridged_multi_fractal_3d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_HETERO_TERRAIN:
+ fac = noise_musgrave_hetero_terrain_3d(p, dimension, lacunarity, detail, foffset);
+ break;
+ default:
+ fac = 0.0f;
+ }
+ break;
+ }
+ case 4: {
+ float4 p = make_float4(co.x, co.y, co.z, w) * scale;
+ switch ((NodeMusgraveType)type) {
+ case NODE_MUSGRAVE_MULTIFRACTAL:
+ fac = noise_musgrave_multi_fractal_4d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_FBM:
+ fac = noise_musgrave_fBm_4d(p, dimension, lacunarity, detail);
+ break;
+ case NODE_MUSGRAVE_HYBRID_MULTIFRACTAL:
+ fac = noise_musgrave_hybrid_multi_fractal_4d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_RIDGED_MULTIFRACTAL:
+ fac = noise_musgrave_ridged_multi_fractal_4d(
+ p, dimension, lacunarity, detail, foffset, gain);
+ break;
+ case NODE_MUSGRAVE_HETERO_TERRAIN:
+ fac = noise_musgrave_hetero_terrain_4d(p, dimension, lacunarity, detail, foffset);
+ break;
+ default:
+ fac = 0.0f;
+ }
+ break;
+ }
+ default:
+ fac = 0.0f;
+ }
if (stack_valid(fac_offset))
- stack_store_float(stack, fac_offset, f);
- if (stack_valid(color_offset))
- stack_store_float3(stack, color_offset, make_float3(f, f, f));
+ stack_store_float(stack, fac_offset, fac);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h
index 322579ccfe3..dd7d7178101 100644
--- a/intern/cycles/kernel/svm/svm_noise.h
+++ b/intern/cycles/kernel/svm/svm_noise.h
@@ -32,304 +32,559 @@
CCL_NAMESPACE_BEGIN
-#ifdef __KERNEL_SSE2__
-ccl_device_inline ssei quick_floor_sse(const ssef &x)
+/* **** Perlin Noise **** */
+
+/* The following functions compute 1D, 2D, 3D, and 4D perlin noise.
+ * The code is based on the OSL noise code for compatibility.
+ * See oslnoise.h
+ */
+
+/* An alternative to Hermite interpolation that have zero first and
+ * second derivatives at t = 0 and t = 1.
+ * Described in Ken Perlin's "Improving noise" [2002].
+ */
+ccl_device float fade(float t)
{
- ssei b = truncatei(x);
- ssei isneg = cast((x < ssef(0.0f)).m128);
- return b + isneg; // unsaturated add 0xffffffff is the same as subtract -1
+ return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
}
-#endif
-ccl_device uint hash(uint kx, uint ky, uint kz)
-{
- // define some handy macros
-#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
-#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); \
- }
- // now hash the data!
- uint a, b, c, len = 3;
- a = b = c = 0xdeadbeef + (len << 2) + 13;
-
- c += kz;
- b += ky;
- a += kx;
- final(a, b, c);
-
- return c;
- // macros not needed anymore
-#undef rot
-#undef final
-}
-
-#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
+ccl_device_inline float negate_if(float val, int condition)
+{
+ return (condition) ? -val : val;
}
-#endif
-#if 0 // unused
-ccl_device int imod(int a, int b)
+ccl_device float grad1(int hash, float x)
{
- a %= b;
- return a < 0 ? a + b : a;
+ int h = hash & 15;
+ float g = 1 + (h & 7);
+ return negate_if(g, h & 8) * x;
}
-ccl_device uint phash(int kx, int ky, int kz, int3 p)
+ccl_device_noinline float perlin_1d(float x)
{
- return hash(imod(kx, p.x), imod(ky, p.y), imod(kz, p.z));
+ 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 do a separate
+ * implementation for the SSE kernels.
+ */
#ifndef __KERNEL_SSE2__
-ccl_device float floorfrac(float x, int *i)
+/* 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)
{
- *i = quick_floor_to_int(x);
- return x - *i;
+ float x1 = 1.0f - x;
+ return (1.0f - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x);
}
-#else
-ccl_device_inline ssef floorfrac_sse(const ssef &x, ssei *i)
+
+/* 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)
{
- *i = quick_floor_sse(x);
- return x - ssef(*i);
+ 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 fade(float t)
+ccl_device float grad2(int hash, float x, float y)
{
- return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
+ 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);
}
-#else
-ccl_device_inline ssef fade_sse(const ssef *t)
+
+ccl_device float grad3(int hash, 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);
+ int h = hash & 15;
+ float u = h < 8 ? x : y;
+ float vt = ((h == 12) || (h == 14)) ? x : z;
+ float v = h < 4 ? y : vt;
+ return negate_if(u, h & 1) + negate_if(v, h & 2);
}
-#endif
-#ifndef __KERNEL_SSE2__
-ccl_device float nerp(float t, float a, float b)
+ccl_device float grad4(int hash, float x, float y, float z, float w)
{
- return (1.0f - t) * a + t * b;
+ 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);
}
-#else
-ccl_device_inline ssef nerp_sse(const ssef &t, const ssef &a, const ssef &b)
+
+ccl_device_noinline float perlin_2d(float x, float y)
{
- ssef x1 = (ssef(1.0f) - t) * a;
- return madd(t, b, x1);
+ int X;
+ int Y;
+
+ float fx = floorfrac(x, &X);
+ float fy = floorfrac(y, &Y);
+
+ float u = fade(fx);
+ float v = fade(fy);
+
+ 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);
+
+ return r;
}
-#endif
-#ifndef __KERNEL_SSE2__
-ccl_device float grad(int hash, float x, float y, float z)
+ccl_device_noinline float perlin_3d(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 v = h < 4 ? y : vt;
- return ((h & 1) ? -u : u) + ((h & 2) ? -v : v);
+ int X;
+ int Y;
+ int Z;
+
+ float fx = floorfrac(x, &X);
+ float fy = floorfrac(y, &Y);
+ float fz = floorfrac(z, &Z);
+
+ float u = fade(fx);
+ float v = fade(fy);
+ float w = fade(fz);
+
+ 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;
}
-#else
-ccl_device_inline ssef grad_sse(const ssei &hash, const ssef &x, const ssef &y, const ssef &z)
+
+ccl_device_noinline float perlin_4d(float x, float y, float z, float w)
{
- ssei c1 = ssei(1);
- ssei c2 = ssei(2);
+ int X;
+ int Y;
+ int Z;
+ int W;
- ssei h = hash & ssei(15); // h = hash & 15
+ float fx = floorfrac(x, &X);
+ float fy = floorfrac(y, &Y);
+ float fz = floorfrac(z, &Z);
+ float fw = floorfrac(w, &W);
- sseb case_ux = h < ssei(8); // 0xffffffff if h < 8 else 0
+ float u = fade(fx);
+ float v = fade(fy);
+ float t = fade(fz);
+ float s = fade(fw);
+
+ float r = mix(
+ tri_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),
+ u,
+ v,
+ t),
+ tri_mix(
+ 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);
- ssef u = select(case_ux, x, y); // u = h<8 ? x : y
+ return r;
+}
- sseb case_vy = h < ssei(4); // 0xffffffff if h < 4 else 0
+#else /* SSE */
+ccl_device_inline ssei quick_floor(const ssef &x)
+{
+ ssei b = truncatei(x);
+ ssei isneg = cast((x < 0.0f).m128);
+ return b + isneg; // unsaturated add 0xffffffff is the same as subtract -1
+}
+
+ccl_device_inline ssef floorfrac(const ssef &x, ssei *i)
+{
+ *i = quick_floor(x);
+ return x - ssef(*i);
+}
- sseb case_h12 = h == ssei(12); // 0xffffffff if h == 12 else 0
- sseb case_h14 = h == ssei(14); // 0xffffffff if h == 14 else 0
+/* 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 shuffling v using the mask <2, 3>.
+ * The third and fourth values of g 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>(p), shuffle<0>(f));
+ return mix(g, shuffle<1>(g), shuffle<1>(f));
+}
- sseb case_vx = case_h12 | case_h14; // 0xffffffff if h == 12 or h == 14 else 0
+/* 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 shuffling s using the mask <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>(s), shuffle<1>(f));
+ return mix(g, shuffle<1>(g), shuffle<2>(f));
+}
- ssef v = select(case_vy, y, select(case_vx, x, z)); // v = h<4 ? y : h == 12 || h == 14 ? x : z
+/* 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));
+}
- 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)
+/* An alternative to Hermite interpolation that have zero first and
+ * second derivatives at t = 0 and t = 1.
+ * Described in Ken Perlin's "Improving noise" [2002].
+ */
+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);
+}
- 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)
+/* 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))))
- ssef r = ru + rv; // ((h&1) ? -u : u) + ((h&2) ? -v : v)
- return r;
+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);
}
-#endif
-#ifndef __KERNEL_SSE2__
-ccl_device float scale3(float result)
+ccl_device_inline ssef grad(const ssei &hash, const ssef &x, const ssef &y, const ssef &z)
{
- return 0.9820f * result;
+ 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);
}
-#else
-ccl_device_inline ssef scale3_sse(const ssef &result)
+
+ccl_device_inline ssef
+grad(const ssei &hash, const ssef &x, const ssef &y, const ssef &z, const ssef &w)
{
- return ssef(0.9820f) * result;
+ 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);
}
-#endif
-#ifndef __KERNEL_SSE2__
-ccl_device_noinline float perlin(float x, float y, float z)
+/* 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)
{
- int X;
- float fx = floorfrac(x, &X);
- int Y;
- float fy = floorfrac(y, &Y);
- int Z;
- float fz = floorfrac(z, &Z);
+ ssei XY;
+ ssef fxy = floorfrac(ssef(x, y, 0.0f, 0.0f), &XY);
+ ssef uv = fade(fxy);
- float u = fade(fx);
- float v = fade(fy);
- float w = fade(fz);
+ 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);
- float result;
-
- result = nerp(
- w,
- nerp(v,
- nerp(u, grad(hash(X, Y, Z), fx, fy, fz), grad(hash(X + 1, Y, Z), fx - 1.0f, fy, fz)),
- nerp(u,
- grad(hash(X, Y + 1, Z), fx, fy - 1.0f, fz),
- grad(hash(X + 1, Y + 1, Z), fx - 1.0f, fy - 1.0f, fz))),
- nerp(v,
- nerp(u,
- grad(hash(X, Y, Z + 1), fx, fy, fz - 1.0f),
- grad(hash(X + 1, Y, Z + 1), fx - 1.0f, fy, fz - 1.0f)),
- nerp(u,
- grad(hash(X, Y + 1, Z + 1), fx, fy - 1.0f, fz - 1.0f),
- grad(hash(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;
-}
-#else
-ccl_device_noinline float perlin(float x, float y, float z)
-{
- ssef xyz = ssef(x, y, z, 0.0f);
+ 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)
+{
ssei XYZ;
+ ssef fxyz = floorfrac(ssef(x, y, z, 0.0f), &XYZ);
+ ssef uvw = fade(fxyz);
+
+ 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));
+
+ ssei h1 = hash_ssei3(shuffle<0>(XYZ), Y, Z);
+ ssei h2 = hash_ssei3(shuffle<0>(XYZ1), Y, Z);
- ssef fxyz = floorfrac_sse(xyz, &XYZ);
+ 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));
- ssef uvw = fade_sse(&fxyz);
- ssef u = shuffle<0>(uvw), v = shuffle<1>(uvw), w = shuffle<2>(uvw);
+ ssef g1 = grad(h1, shuffle<0>(fxyz), fy, fz);
+ ssef g2 = grad(h2, shuffle<0>(fxyz1), fy, fz);
- 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
+ return extract<0>(tri_mix(g1, g2, uvw));
+}
+
+/* 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);
- 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
+ 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 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));
+ 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 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);
+ 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 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', _, _]
+ 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 n2_second = shuffle<1>(n2); // extract b to a separate vector
- ssef result = nerp_sse(
- w, n2, n2_second); // process nerp([a', _, _, _], [b', _, _, _]) -> [a'', _, _, _]
+ 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 r = scale3_sse(result);
+ ssef g3 = grad(h3, shuffle<0>(fxyzw), fy, fz, shuffle<3>(fxyzw1));
+ ssef g4 = grad(h4, shuffle<0>(fxyzw1), fy, fz, shuffle<3>(fxyzw1));
- 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);
+ 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 values were computed experimentally by the OSL developers.
+ */
+
+ccl_device_inline float scale1(float result)
{
- float r = perlin(p.x, p.y, p.z);
- return 0.5f * r + 0.5f;
+ return 0.2500f * result;
}
-/* perlin noise in range -1..1 */
-ccl_device float snoise(float3 p)
+ccl_device_inline float scale2(float result)
{
- return perlin(p.x, p.y, p.z);
+ return 0.6616f * result;
}
-/* cell noise */
-ccl_device float cellnoise(float3 p)
+ccl_device_inline float scale3(float result)
{
- int3 ip = quick_floor_to_int3(p);
- return bits_to_01(hash(ip.x, ip.y, ip.z));
+ return 0.9820f * result;
}
-ccl_device float3 cellnoise3(float3 p)
+ccl_device_inline float scale4(float result)
{
- int3 ip = quick_floor_to_int3(p);
-#ifndef __KERNEL_SSE__
- float r = bits_to_01(hash(ip.x, ip.y, ip.z));
- float g = bits_to_01(hash(ip.y, ip.x, ip.z));
- float b = bits_to_01(hash(ip.y, ip.z, ip.x));
- return make_float3(r, g, b);
-#else
- 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);
- return float3(uint32_to_float(bits) * ssef(1.0f / (float)0xFFFFFFFF));
-#endif
+ return 0.8344f * result;
+}
+
+ccl_device_inline float snoise_1d(float p)
+{
+ float r = perlin_1d(p);
+ return isinf(r) ? 0.0f : 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 : 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 : 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_4d(p.x, p.y, p.z, p.w);
+ return isinf(r) ? 0.0f : scale4(r);
+}
+
+ccl_device_inline float noise_4d(float4 p)
+{
+ return 0.5f * snoise_4d(p) + 0.5f;
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_noisetex.h b/intern/cycles/kernel/svm/svm_noisetex.h
index 3324e86fcd8..c74c118c42e 100644
--- a/intern/cycles/kernel/svm/svm_noisetex.h
+++ b/intern/cycles/kernel/svm/svm_noisetex.h
@@ -16,43 +16,168 @@
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);
+}
- decode_node_uchar4(node.y, &co_offset, &scale_offset, &detail_offset, &distortion_offset);
- decode_node_uchar4(node.z, &color_offset, &fac_offset, NULL, NULL);
+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 = noise_turbulence_1d(p, detail);
+ if (color_is_needed) {
+ *color = make_float3(*value,
+ noise_turbulence_1d(p + random_float_offset(1.0f), detail),
+ noise_turbulence_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 = noise_turbulence_2d(p, detail);
+ if (color_is_needed) {
+ *color = make_float3(*value,
+ noise_turbulence_2d(p + random_float2_offset(2.0f), detail),
+ noise_turbulence_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 = noise_turbulence_3d(p, detail);
+ if (color_is_needed) {
+ *color = make_float3(*value,
+ noise_turbulence_3d(p + random_float3_offset(3.0f), detail),
+ noise_turbulence_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 = noise_turbulence_4d(p, detail);
+ if (color_is_needed) {
+ *color = make_float3(*value,
+ noise_turbulence_4d(p + random_float4_offset(4.0f), detail),
+ noise_turbulence_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_offset, w_offset, scale_offset, detail_offset, distortion_offset, value_offset,
+ color_offset;
+
+ decode_node_uchar4(offsets1, &vector_offset, &w_offset, &scale_offset, &detail_offset);
+ decode_node_uchar4(offsets2, &distortion_offset, &value_offset, &color_offset, NULL);
+
+ uint4 node1 = read_node(kg, offset);
+
+ float3 vector = stack_load_float3(stack, vector_offset);
+ float w = stack_load_float_default(stack, w_offset, node1.x);
+ float scale = stack_load_float_default(stack, scale_offset, node1.y);
+ float detail = stack_load_float_default(stack, detail_offset, node1.z);
+ float distortion = stack_load_float_default(stack, distortion_offset, node1.w);
+
+ vector *= scale;
+ w *= scale;
+
+ float value;
+ float3 color;
+ switch (dimensions) {
+ case 1:
+ noise_texture_1d(w, detail, distortion, stack_valid(color_offset), &value, &color);
+ break;
+ case 2:
+ noise_texture_2d(make_float2(vector.x, vector.y),
+ detail,
+ distortion,
+ stack_valid(color_offset),
+ &value,
+ &color);
+ break;
+ case 3:
+ noise_texture_3d(vector, detail, distortion, stack_valid(color_offset), &value, &color);
+ break;
+ case 4:
+ noise_texture_4d(make_float4(vector.x, vector.y, vector.z, w),
+ detail,
+ distortion,
+ stack_valid(color_offset),
+ &value,
+ &color);
+ break;
+ default:
+ kernel_assert(0);
+ }
- if (stack_valid(fac_offset)) {
- stack_store_float(stack, fac_offset, f);
+ if (stack_valid(value_offset)) {
+ stack_store_float(stack, value_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);
}
}
diff --git a/intern/cycles/kernel/svm/svm_texture.h b/intern/cycles/kernel/svm/svm_texture.h
index 290aa85c831..40c2c40b77b 100644
--- a/intern/cycles/kernel/svm/svm_texture.h
+++ b/intern/cycles/kernel/svm/svm_texture.h
@@ -18,40 +18,111 @@ CCL_NAMESPACE_BEGIN
/* Turbulence */
-ccl_device_noinline float noise_turbulence(float3 p, float octaves, int hard)
+/* The following 4 functions are exactly the same but with different input type.
+ * When refactoring, simply copy the function body to the rest of the functions
+ * and replace noise_[1234]d with the appropriate function.
+ */
+
+ccl_device_noinline float noise_turbulence_1d(float p, float octaves)
{
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);
-
+ 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(fscale * p);
-
- if (hard)
- t = fabsf(2.0f * t - 1.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;
+ }
+}
+ccl_device_noinline float noise_turbulence_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;
+ }
+}
+ccl_device_noinline float noise_turbulence_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;
+ }
+}
+ccl_device_noinline float noise_turbulence_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 {
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index ea92fd7ce59..d7808065211 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -138,12 +138,20 @@ typedef enum ShaderNodeType {
NODE_VECTOR_DISPLACEMENT,
NODE_PRINCIPLED_VOLUME,
NODE_IES,
+ NODE_TEXTURE_MAPPING,
+ NODE_MAP_RANGE,
+ NODE_CLAMP,
+ NODE_TEX_WHITE_NOISE,
+ NODE_VERTEX_COLOR,
+ NODE_VERTEX_COLOR_BUMP_DX,
+ NODE_VERTEX_COLOR_BUMP_DY,
} ShaderNodeType;
typedef enum NodeAttributeType {
NODE_ATTR_FLOAT = 0,
NODE_ATTR_FLOAT2,
NODE_ATTR_FLOAT3,
+ NODE_ATTR_RGBA,
NODE_ATTR_MATRIX
} NodeAttributeType;
@@ -158,6 +166,7 @@ typedef enum NodeGeometry {
typedef enum NodeObjectInfo {
NODE_INFO_OB_LOCATION,
+ NODE_INFO_OB_COLOR,
NODE_INFO_OB_INDEX,
NODE_INFO_MAT_INDEX,
NODE_INFO_OB_RANDOM
@@ -242,7 +251,7 @@ typedef enum NodeMix {
NODE_MIX_CLAMP /* used for the clamp UI option */
} NodeMix;
-typedef enum NodeMath {
+typedef enum NodeMathType {
NODE_MATH_ADD,
NODE_MATH_SUBTRACT,
NODE_MATH_MULTIPLY,
@@ -265,19 +274,42 @@ typedef enum NodeMath {
NODE_MATH_ARCTAN2,
NODE_MATH_FLOOR,
NODE_MATH_CEIL,
- NODE_MATH_FRACT,
+ NODE_MATH_FRACTION,
NODE_MATH_SQRT,
- NODE_MATH_CLAMP /* used for the clamp UI option */
-} NodeMath;
+} NodeMathType;
-typedef enum NodeVectorMath {
+typedef enum NodeVectorMathType {
NODE_VECTOR_MATH_ADD,
NODE_VECTOR_MATH_SUBTRACT,
- NODE_VECTOR_MATH_AVERAGE,
- NODE_VECTOR_MATH_DOT_PRODUCT,
+ NODE_VECTOR_MATH_MULTIPLY,
+ NODE_VECTOR_MATH_DIVIDE,
+
NODE_VECTOR_MATH_CROSS_PRODUCT,
- NODE_VECTOR_MATH_NORMALIZE
-} NodeVectorMath;
+ NODE_VECTOR_MATH_PROJECT,
+ NODE_VECTOR_MATH_REFLECT,
+ NODE_VECTOR_MATH_DOT_PRODUCT,
+
+ NODE_VECTOR_MATH_DISTANCE,
+ NODE_VECTOR_MATH_LENGTH,
+ NODE_VECTOR_MATH_SCALE,
+ NODE_VECTOR_MATH_NORMALIZE,
+
+ NODE_VECTOR_MATH_SNAP,
+ NODE_VECTOR_MATH_FLOOR,
+ NODE_VECTOR_MATH_CEIL,
+ NODE_VECTOR_MATH_MODULO,
+ NODE_VECTOR_MATH_FRACTION,
+ NODE_VECTOR_MATH_ABSOLUTE,
+ NODE_VECTOR_MATH_MINIMUM,
+ 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,
@@ -329,13 +361,8 @@ typedef enum NodeGradientType {
NODE_BLEND_SPHERICAL
} NodeGradientType;
-typedef enum NodeVoronoiColoring {
- NODE_VORONOI_INTENSITY,
- NODE_VORONOI_CELLS
-} NodeVoronoiColoring;
-
typedef enum NodeVoronoiDistanceMetric {
- NODE_VORONOI_DISTANCE,
+ NODE_VORONOI_EUCLIDEAN,
NODE_VORONOI_MANHATTAN,
NODE_VORONOI_CHEBYCHEV,
NODE_VORONOI_MINKOWSKI
@@ -343,10 +370,10 @@ typedef enum NodeVoronoiDistanceMetric {
typedef enum NodeVoronoiFeature {
NODE_VORONOI_F1,
+ NODE_VORONOI_SMOOTH_F1,
NODE_VORONOI_F2,
- NODE_VORONOI_F3,
- NODE_VORONOI_F4,
- NODE_VORONOI_F2F1
+ NODE_VORONOI_DISTANCE_TO_EDGE,
+ NODE_VORONOI_N_SPHERE_RADIUS,
} NodeVoronoiFeature;
typedef enum NodeBlendWeightType {
diff --git a/intern/cycles/kernel/svm/svm_vertex_color.h b/intern/cycles/kernel/svm/svm_vertex_color.h
new file mode 100644
index 00000000000..3c105b1cbfa
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_vertex_color.h
@@ -0,0 +1,92 @@
+/*
+ * 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
+
+ccl_device void svm_node_vertex_color(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint layer_id,
+ uint color_offset,
+ uint alpha_offset)
+{
+ AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
+ if (descriptor.offset != ATTR_STD_NOT_FOUND) {
+ float4 vertex_color = primitive_attribute_float4(kg, sd, descriptor, NULL, NULL);
+ stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
+ stack_store_float(stack, alpha_offset, vertex_color.w);
+ }
+ else {
+ stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
+ stack_store_float(stack, alpha_offset, 0.0f);
+ }
+}
+
+#ifndef __KERNEL_CUDA__
+ccl_device
+#else
+ccl_device_noinline
+#endif
+ void
+ svm_node_vertex_color_bump_dx(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint layer_id,
+ uint color_offset,
+ uint alpha_offset)
+{
+ AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
+ if (descriptor.offset != ATTR_STD_NOT_FOUND) {
+ float4 dx;
+ float4 vertex_color = primitive_attribute_float4(kg, sd, descriptor, &dx, NULL);
+ vertex_color += dx;
+ stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
+ stack_store_float(stack, alpha_offset, vertex_color.w);
+ }
+ else {
+ stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
+ stack_store_float(stack, alpha_offset, 0.0f);
+ }
+}
+
+#ifndef __KERNEL_CUDA__
+ccl_device
+#else
+ccl_device_noinline
+#endif
+ void
+ svm_node_vertex_color_bump_dy(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint layer_id,
+ uint color_offset,
+ uint alpha_offset)
+{
+ AttributeDescriptor descriptor = find_attribute(kg, sd, layer_id);
+ if (descriptor.offset != ATTR_STD_NOT_FOUND) {
+ float4 dy;
+ float4 vertex_color = primitive_attribute_float4(kg, sd, descriptor, NULL, &dy);
+ vertex_color += dy;
+ stack_store_float3(stack, color_offset, float4_to_float3(vertex_color));
+ stack_store_float(stack, alpha_offset, vertex_color.w);
+ }
+ else {
+ stack_store_float3(stack, color_offset, make_float3(0.0f, 0.0f, 0.0f));
+ stack_store_float(stack, alpha_offset, 0.0f);
+ }
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_voronoi.h b/intern/cycles/kernel/svm/svm_voronoi.h
index 3e28a316169..46bedc80b1f 100644
--- a/intern/cycles/kernel/svm/svm_voronoi.h
+++ b/intern/cycles/kernel/svm/svm_voronoi.h
@@ -16,170 +16,1038 @@
CCL_NAMESPACE_BEGIN
-/* Voronoi */
-
-ccl_device void voronoi_neighbors(
- float3 p, NodeVoronoiDistanceMetric distance, float e, float da[4], float3 pa[4])
-{
- /* Compute the distance to and the position of the closest neighbors to p.
- *
- * The neighbors are randomly placed, 1 each in a 3x3x3 grid (Worley pattern).
- * The distances and points are returned in ascending order, i.e. da[0] and pa[0] will
- * contain the distance to the closest point and its coordinates respectively.
- */
-
- da[0] = 1e10f;
- da[1] = 1e10f;
- da[2] = 1e10f;
- da[3] = 1e10f;
-
- pa[0] = make_float3(0.0f, 0.0f, 0.0f);
- pa[1] = make_float3(0.0f, 0.0f, 0.0f);
- pa[2] = make_float3(0.0f, 0.0f, 0.0f);
- pa[3] = make_float3(0.0f, 0.0f, 0.0f);
-
- int3 xyzi = quick_floor_to_int3(p);
-
- for (int xx = -1; xx <= 1; xx++) {
- for (int yy = -1; yy <= 1; yy++) {
- for (int zz = -1; zz <= 1; zz++) {
- int3 ip = xyzi + make_int3(xx, yy, zz);
- float3 fp = make_float3(ip.x, ip.y, ip.z);
- float3 vp = fp + cellnoise3(fp);
-
- float d;
- switch (distance) {
- case NODE_VORONOI_DISTANCE:
- d = len_squared(p - vp);
- break;
- case NODE_VORONOI_MANHATTAN:
- d = reduce_add(fabs(vp - p));
- break;
- case NODE_VORONOI_CHEBYCHEV:
- d = max3(fabs(vp - p));
- break;
- case NODE_VORONOI_MINKOWSKI: {
- float3 n = fabs(vp - p);
- if (e == 0.5f) {
- d = sqr(reduce_add(sqrt(n)));
- }
- else {
- d = powf(reduce_add(pow3(n, e)), 1.0f / e);
- }
- break;
+/* **** Voronoi Texture **** */
+
+// Each of the following functions computes a certain voronoi feature in a certain dimension.
+// Independent functions are used because every feature/dimension have a different search area.
+//
+// This code is based on the following:
+// Base code : http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm
+// Smoothing : https://iquilezles.untergrund.net/www/articles/smin/smin.htm
+// Distance To Edge Method : https://www.shadertoy.com/view/llG3zy
+
+/* **** 1D Voronoi **** */
+
+ccl_device float voronoi_distance_1d(float a,
+ float b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ return fabsf(b - a);
+}
+
+ccl_device void voronoi_f1_1d(float w,
+ float exponent,
+ float jitter,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float *outW)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float minDistance = 8.0f;
+ float targetOffset, targetPosition;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float_to_float3(cellPosition + targetOffset);
+ *outW = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_1d(float w,
+ float smoothness,
+ float exponent,
+ float jitter,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float *outW)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float smoothDistance = 0.0f;
+ float smoothPosition = 0.0f;
+ for (int i = -2; i <= 2; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
+ float weight = expf(-smoothness * distanceToPoint);
+ smoothDistance += weight;
+ smoothColor += hash_float_to_float3(cellPosition + cellOffset) * weight;
+ smoothPosition += pointPosition * weight;
+ }
+ *outDistance = -logf(smoothDistance) / smoothness;
+ *outColor = smoothColor / smoothDistance;
+ *outW = cellPosition + smoothPosition / smoothDistance;
+}
+
+ccl_device void voronoi_f2_1d(float w,
+ float exponent,
+ float jitter,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float *outW)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float offsetF1 = 0.0f;
+ float positionF1 = 0.0f;
+ float offsetF2, positionF2;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance_1d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float_to_float3(cellPosition + offsetF2);
+ *outW = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_1d(float w, float jitter, float *outDistance)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float minDistance = 8.0f;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = fabsf(pointPosition - localPosition);
+ minDistance = min(distanceToPoint, minDistance);
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_1d(float w, float jitter, float *outRadius)
+{
+ float cellPosition = floorf(w);
+ float localPosition = w - cellPosition;
+
+ float closestPoint;
+ float closestPointOffset;
+ float minDistance = 8.0f;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = i;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = fabsf(pointPosition - localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+
+ minDistance = 8.0f;
+ float closestPointToClosestPoint;
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0)
+ continue;
+ float cellOffset = i + closestPointOffset;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = fabsf(closestPoint - pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ *outRadius = fabsf(closestPointToClosestPoint - closestPoint) / 2.0f;
+}
+
+/* **** 2D Voronoi **** */
+
+ccl_device float voronoi_distance_2d(float2 a,
+ float2 b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ if (metric == NODE_VORONOI_EUCLIDEAN)
+ return distance(a, b);
+ else if (metric == NODE_VORONOI_MANHATTAN)
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y);
+ else if (metric == NODE_VORONOI_CHEBYCHEV)
+ return max(fabsf(a.x - b.x), fabsf(a.y - b.y));
+ else if (metric == NODE_VORONOI_MINKOWSKI)
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent),
+ 1.0f / exponent);
+ else
+ return 0.0f;
+}
+
+ccl_device void voronoi_f1_2d(float2 coord,
+ float exponent,
+ float jitter,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float2 *outPosition)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float2 targetOffset, targetPosition;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float2_to_float3(cellPosition + targetOffset);
+ *outPosition = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_2d(float2 coord,
+ float smoothness,
+ float exponent,
+ float jitter,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float2 *outPosition)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float smoothDistance = 0.0f;
+ float2 smoothPosition = make_float2(0.0f, 0.0f);
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
+ float weight = expf(-smoothness * distanceToPoint);
+ smoothDistance += weight;
+ smoothColor += hash_float2_to_float3(cellPosition + cellOffset) * weight;
+ smoothPosition += pointPosition * weight;
+ }
+ }
+ *outDistance = -logf(smoothDistance) / smoothness;
+ *outColor = smoothColor / smoothDistance;
+ *outPosition = cellPosition + smoothPosition / smoothDistance;
+}
+
+ccl_device void voronoi_f2_2d(float2 coord,
+ float exponent,
+ float jitter,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float2 *outPosition)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float2 offsetF1 = make_float2(0.0f, 0.0f);
+ float2 positionF1 = make_float2(0.0f, 0.0f);
+ float2 offsetF2, positionF2;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance_2d(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float2_to_float3(cellPosition + offsetF2);
+ *outPosition = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_2d(float2 coord, float jitter, float *outDistance)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float2 vectorToClosest;
+ float minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 vectorToPoint = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * jitter -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 vectorToPoint = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * jitter -
+ localPosition;
+ float2 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_2d(float2 coord, float jitter, float *outRadius)
+{
+ float2 cellPosition = floor(coord);
+ float2 localPosition = coord - cellPosition;
+
+ float2 closestPoint;
+ float2 closestPointOffset;
+ float minDistance = 8.0f;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float2 cellOffset = make_float2(i, j);
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float2 closestPointToClosestPoint;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0)
+ continue;
+ float2 cellOffset = make_float2(i, j) + closestPointOffset;
+ float2 pointPosition = cellOffset +
+ hash_float2_to_float2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+/* **** 3D Voronoi **** */
+
+ccl_device float voronoi_distance_3d(float3 a,
+ float3 b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ if (metric == NODE_VORONOI_EUCLIDEAN)
+ return distance(a, b);
+ else if (metric == NODE_VORONOI_MANHATTAN)
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z);
+ else if (metric == NODE_VORONOI_CHEBYCHEV)
+ return max(fabsf(a.x - b.x), max(fabsf(a.y - b.y), fabsf(a.z - b.z)));
+ else if (metric == NODE_VORONOI_MINKOWSKI)
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
+ powf(fabsf(a.z - b.z), exponent),
+ 1.0f / exponent);
+ else
+ return 0.0f;
+}
+
+ccl_device void voronoi_f1_3d(float3 coord,
+ float exponent,
+ float jitter,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float3 *outPosition)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float3 targetOffset, targetPosition;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance_3d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float3_to_float3(cellPosition + targetOffset);
+ *outPosition = targetPosition + cellPosition;
+}
+
+ccl_device void voronoi_smooth_f1_3d(float3 coord,
+ float smoothness,
+ float exponent,
+ float jitter,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float3 *outPosition)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float smoothDistance = 0.0f;
+ float3 smoothPosition = make_float3(0.0f, 0.0f, 0.0f);
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance_3d(
+ pointPosition, localPosition, metric, exponent);
+ float weight = expf(-smoothness * distanceToPoint);
+ smoothDistance += weight;
+ smoothColor += hash_float3_to_float3(cellPosition + cellOffset) * weight;
+ smoothPosition += pointPosition * weight;
+ }
+ }
+ }
+ *outDistance = -logf(smoothDistance) / smoothness;
+ *outColor = smoothColor / smoothDistance;
+ *outPosition = cellPosition + smoothPosition / smoothDistance;
+}
+
+ccl_device void voronoi_f2_3d(float3 coord,
+ float exponent,
+ float jitter,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float3 *outPosition)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float3 offsetF1 = make_float3(0.0f, 0.0f, 0.0f);
+ float3 positionF1 = make_float3(0.0f, 0.0f, 0.0f);
+ float3 offsetF2, positionF2;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance_3d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float3_to_float3(cellPosition + offsetF2);
+ *outPosition = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_3d(float3 coord, float jitter, float *outDistance)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float3 vectorToClosest;
+ float minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 vectorToPoint = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * jitter -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 vectorToPoint = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * jitter -
+ localPosition;
+ float3 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_3d(float3 coord, float jitter, float *outRadius)
+{
+ float3 cellPosition = floor(coord);
+ float3 localPosition = coord - cellPosition;
+
+ float3 closestPoint;
+ float3 closestPointOffset;
+ float minDistance = 8.0f;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float3 cellOffset = make_float3(i, j, k);
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float3 closestPointToClosestPoint;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0)
+ continue;
+ float3 cellOffset = make_float3(i, j, k) + closestPointOffset;
+ float3 pointPosition = cellOffset +
+ hash_float3_to_float3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
+ *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
+}
+
+/* **** 4D Voronoi **** */
+
+ccl_device float voronoi_distance_4d(float4 a,
+ float4 b,
+ NodeVoronoiDistanceMetric metric,
+ float exponent)
+{
+ if (metric == NODE_VORONOI_EUCLIDEAN)
+ return distance(a, b);
+ else if (metric == NODE_VORONOI_MANHATTAN)
+ return fabsf(a.x - b.x) + fabsf(a.y - b.y) + fabsf(a.z - b.z) + fabsf(a.w - b.w);
+ else if (metric == NODE_VORONOI_CHEBYCHEV)
+ return max(fabsf(a.x - b.x), max(fabsf(a.y - b.y), max(fabsf(a.z - b.z), fabsf(a.w - b.w))));
+ else if (metric == NODE_VORONOI_MINKOWSKI)
+ return powf(powf(fabsf(a.x - b.x), exponent) + powf(fabsf(a.y - b.y), exponent) +
+ powf(fabsf(a.z - b.z), exponent) + powf(fabsf(a.w - b.w), exponent),
+ 1.0f / exponent);
+ else
+ return 0.0f;
+}
+
+ccl_device void voronoi_f1_4d(float4 coord,
+ float exponent,
+ float jitter,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float4 *outPosition)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float minDistance = 8.0f;
+ float4 targetOffset, targetPosition;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance_4d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
}
}
+ }
+ }
+ }
+ *outDistance = minDistance;
+ *outColor = hash_float4_to_float3(cellPosition + targetOffset);
+ *outPosition = targetPosition + cellPosition;
+}
- /* To keep the shortest four distances and associated points we have to keep them in sorted
- * order. */
- 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;
+ccl_device void voronoi_smooth_f1_4d(float4 coord,
+ float smoothness,
+ float exponent,
+ float jitter,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float4 *outPosition)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float3 smoothColor = make_float3(0.0f, 0.0f, 0.0f);
+ float smoothDistance = 0.0f;
+ float4 smoothPosition = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ for (int u = -2; u <= 2; u++) {
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance_4d(
+ pointPosition, localPosition, metric, exponent);
+ float weight = expf(-smoothness * distanceToPoint);
+ smoothDistance += weight;
+ smoothColor += hash_float4_to_float3(cellPosition + cellOffset) * weight;
+ smoothPosition += pointPosition * weight;
}
- 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;
+ }
+ }
+ }
+ *outDistance = -logf(smoothDistance) / smoothness;
+ *outColor = smoothColor / smoothDistance;
+ *outPosition = cellPosition + smoothPosition / smoothDistance;
+}
+
+ccl_device void voronoi_f2_4d(float4 coord,
+ float exponent,
+ float jitter,
+ NodeVoronoiDistanceMetric metric,
+ float *outDistance,
+ float3 *outColor,
+ float4 *outPosition)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float distanceF1 = 8.0f;
+ float distanceF2 = 8.0f;
+ float4 offsetF1 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 positionF1 = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ float4 offsetF2, positionF2;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance_4d(
+ pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
}
- else if (d < da[2]) {
- da[3] = da[2];
- da[2] = d;
+ }
+ }
+ }
+ *outDistance = distanceF2;
+ *outColor = hash_float4_to_float3(cellPosition + offsetF2);
+ *outPosition = positionF2 + cellPosition;
+}
+
+ccl_device void voronoi_distance_to_edge_4d(float4 coord, float jitter, float *outDistance)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
+
+ float4 vectorToClosest;
+ float minDistance = 8.0f;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 vectorToPoint = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * jitter -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 vectorToPoint = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * jitter -
+ localPosition;
+ float4 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001f) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0f,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ }
+ }
+ *outDistance = minDistance;
+}
+
+ccl_device void voronoi_n_sphere_radius_4d(float4 coord, float jitter, float *outRadius)
+{
+ float4 cellPosition = floor(coord);
+ float4 localPosition = coord - cellPosition;
- pa[3] = pa[2];
- pa[2] = vp;
+ float4 closestPoint;
+ float4 closestPointOffset;
+ float minDistance = 8.0f;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ float4 cellOffset = make_float4(i, j, k, u);
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
}
- else if (d < da[3]) {
- da[3] = d;
- pa[3] = vp;
+ }
+ }
+ }
+
+ minDistance = 8.0f;
+ float4 closestPointToClosestPoint;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0 && u == 0)
+ continue;
+ float4 cellOffset = make_float4(i, j, k, u) + closestPointOffset;
+ float4 pointPosition = cellOffset +
+ hash_float4_to_float4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
}
}
}
}
+ *outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0f;
}
-ccl_device void svm_node_tex_voronoi(
- KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+ccl_device void svm_node_tex_voronoi(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint dimensions,
+ uint feature,
+ uint metric,
+ int *offset)
{
+ uint4 node1 = read_node(kg, offset);
uint4 node2 = read_node(kg, offset);
- uint co_offset, coloring, distance, feature;
- uint scale_offset, e_offset, fac_offset, color_offset;
+ uint coord_offset, w_offset, scale_offset, smoothness_offset;
+ uint exponent_offset, jitter_offset, distance_out_offset, color_out_offset;
+ uint position_out_offset, w_out_offset, radius_out_offset;
- decode_node_uchar4(node.y, &co_offset, &coloring, &distance, &feature);
- decode_node_uchar4(node.z, &scale_offset, &e_offset, &fac_offset, &color_offset);
+ decode_node_uchar4(node1.x, &coord_offset, &w_offset, &scale_offset, &smoothness_offset);
+ decode_node_uchar4(
+ node1.y, &exponent_offset, &jitter_offset, &distance_out_offset, &color_out_offset);
+ decode_node_uchar4(node1.z, &position_out_offset, &w_out_offset, &radius_out_offset, NULL);
- float3 co = stack_load_float3(stack, co_offset);
+ float3 coord = stack_load_float3(stack, coord_offset);
+ float w = stack_load_float_default(stack, w_offset, node1.w);
float scale = stack_load_float_default(stack, scale_offset, node2.x);
- float exponent = stack_load_float_default(stack, e_offset, node2.y);
-
- float dist[4];
- float3 neighbor[4];
- voronoi_neighbors(co * scale, (NodeVoronoiDistanceMetric)distance, exponent, dist, neighbor);
-
- float3 color;
- float fac;
- if (coloring == NODE_VORONOI_INTENSITY) {
- switch (feature) {
- case NODE_VORONOI_F1:
- fac = dist[0];
- break;
- case NODE_VORONOI_F2:
- fac = dist[1];
- break;
- case NODE_VORONOI_F3:
- fac = dist[2];
- break;
- case NODE_VORONOI_F4:
- fac = dist[3];
- break;
- case NODE_VORONOI_F2F1:
- fac = dist[1] - dist[0];
- break;
- }
-
- color = make_float3(fac, fac, fac);
- }
- else {
- /* NODE_VORONOI_CELLS */
- switch (feature) {
- case NODE_VORONOI_F1:
- color = neighbor[0];
- break;
- case NODE_VORONOI_F2:
- color = neighbor[1];
- break;
- case NODE_VORONOI_F3:
- color = neighbor[2];
- break;
- case NODE_VORONOI_F4:
- color = neighbor[3];
- break;
- /* Usefulness of this vector is questionable. Note F2 >= F1 but the
- * individual vector components might not be. */
- case NODE_VORONOI_F2F1:
- color = fabs(neighbor[1] - neighbor[0]);
- break;
- }
-
- color = cellnoise3(color);
- fac = average(color);
- }
-
- if (stack_valid(fac_offset))
- stack_store_float(stack, fac_offset, fac);
- if (stack_valid(color_offset))
- stack_store_float3(stack, color_offset, color);
+ float smoothness = stack_load_float_default(stack, smoothness_offset, node2.y);
+ float exponent = stack_load_float_default(stack, exponent_offset, node2.z);
+ float jitter = stack_load_float_default(stack, jitter_offset, node2.w);
+
+ NodeVoronoiFeature voronoi_feature = (NodeVoronoiFeature)feature;
+ NodeVoronoiDistanceMetric voronoi_metric = (NodeVoronoiDistanceMetric)metric;
+
+ float distance_out, w_out, radius_out;
+ float3 color_out, position_out;
+
+ jitter = clamp(jitter, 0.0f, 1.0f);
+ smoothness = max(smoothness, 1.0f);
+
+ w *= scale;
+ coord *= scale;
+
+ switch (dimensions) {
+ case 1: {
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_1d(w, exponent, jitter, voronoi_metric, &distance_out, &color_out, &w_out);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_1d(
+ w, smoothness, exponent, jitter, voronoi_metric, &distance_out, &color_out, &w_out);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_1d(w, exponent, jitter, voronoi_metric, &distance_out, &color_out, &w_out);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_1d(w, jitter, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_1d(w, jitter, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ w_out = safe_divide(w_out, scale);
+ break;
+ }
+ case 2: {
+ float2 coord_2d = make_float2(coord.x, coord.y);
+ float2 position_out_2d;
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_2d(coord_2d,
+ exponent,
+ jitter,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_2d);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_2d(coord_2d,
+ smoothness,
+ exponent,
+ jitter,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_2d);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_2d(coord_2d,
+ exponent,
+ jitter,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_2d);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_2d(coord_2d, jitter, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_2d(coord_2d, jitter, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ position_out_2d = safe_divide_float2_float(position_out_2d, scale);
+ position_out = make_float3(position_out_2d.x, position_out_2d.y, 0.0f);
+ break;
+ }
+ case 3: {
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_3d(
+ coord, exponent, jitter, voronoi_metric, &distance_out, &color_out, &position_out);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_3d(coord,
+ smoothness,
+ exponent,
+ jitter,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_3d(
+ coord, exponent, jitter, voronoi_metric, &distance_out, &color_out, &position_out);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_3d(coord, jitter, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_3d(coord, jitter, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ position_out = safe_divide_float3_float(position_out, scale);
+ break;
+ }
+ case 4: {
+ float4 coord_4d = make_float4(coord.x, coord.y, coord.z, w);
+ float4 position_out_4d;
+ switch (voronoi_feature) {
+ case NODE_VORONOI_F1:
+ voronoi_f1_4d(coord_4d,
+ exponent,
+ jitter,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_4d);
+ break;
+ case NODE_VORONOI_SMOOTH_F1:
+ voronoi_smooth_f1_4d(coord_4d,
+ smoothness,
+ exponent,
+ jitter,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_4d);
+ break;
+ case NODE_VORONOI_F2:
+ voronoi_f2_4d(coord_4d,
+ exponent,
+ jitter,
+ voronoi_metric,
+ &distance_out,
+ &color_out,
+ &position_out_4d);
+ break;
+ case NODE_VORONOI_DISTANCE_TO_EDGE:
+ voronoi_distance_to_edge_4d(coord_4d, jitter, &distance_out);
+ break;
+ case NODE_VORONOI_N_SPHERE_RADIUS:
+ voronoi_n_sphere_radius_4d(coord_4d, jitter, &radius_out);
+ break;
+ default:
+ kernel_assert(0);
+ }
+ position_out_4d = safe_divide_float4_float(position_out_4d, scale);
+ position_out = make_float3(position_out_4d.x, position_out_4d.y, position_out_4d.z);
+ w_out = position_out_4d.w;
+ break;
+ }
+ default:
+ kernel_assert(0);
+ }
+
+ if (stack_valid(distance_out_offset))
+ stack_store_float(stack, distance_out_offset, distance_out);
+ if (stack_valid(color_out_offset))
+ stack_store_float3(stack, color_out_offset, color_out);
+ if (stack_valid(position_out_offset))
+ stack_store_float3(stack, position_out_offset, position_out);
+ if (stack_valid(w_out_offset))
+ stack_store_float(stack, w_out_offset, w_out);
+ if (stack_valid(radius_out_offset))
+ stack_store_float(stack, radius_out_offset, radius_out);
}
CCL_NAMESPACE_END
diff --git a/intern/cycles/kernel/svm/svm_wave.h b/intern/cycles/kernel/svm/svm_wave.h
index 003ad7dc63a..00b68b8c30b 100644
--- a/intern/cycles/kernel/svm/svm_wave.h
+++ b/intern/cycles/kernel/svm/svm_wave.h
@@ -33,7 +33,7 @@ ccl_device_noinline float svm_wave(NodeWaveType type,
n = len(p) * 20.0f;
if (distortion != 0.0f)
- n += distortion * noise_turbulence(p * dscale, detail, 0);
+ n += distortion * noise_turbulence_3d(p * dscale, detail);
if (profile == NODE_WAVE_PROFILE_SIN) {
return 0.5f + 0.5f * sinf(n);
diff --git a/intern/cycles/kernel/svm/svm_white_noise.h b/intern/cycles/kernel/svm/svm_white_noise.h
new file mode 100644
index 00000000000..56823123366
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_white_noise.h
@@ -0,0 +1,52 @@
+/*
+ * 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
+
+ccl_device void svm_node_tex_white_noise(KernelGlobals *kg,
+ ShaderData *sd,
+ float *stack,
+ uint dimensions,
+ uint vector_offset,
+ uint w_offset,
+ int *offset)
+{
+ uint4 node1 = read_node(kg, offset);
+
+ float3 vector = stack_load_float3(stack, vector_offset);
+ float w = stack_load_float(stack, w_offset);
+
+ float value;
+ switch (dimensions) {
+ case 1:
+ value = hash_float_to_float(w);
+ break;
+ case 2:
+ value = hash_float2_to_float(make_float2(vector.x, vector.y));
+ break;
+ case 3:
+ value = hash_float3_to_float(vector);
+ break;
+ case 4:
+ value = hash_float4_to_float(make_float4(vector.x, vector.y, vector.z, w));
+ break;
+ default:
+ kernel_assert(0);
+ }
+ stack_store_float(stack, node1.y, value);
+}
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp
index f1341d50b9d..0fa1142f354 100644
--- a/intern/cycles/render/attribute.cpp
+++ b/intern/cycles/render/attribute.cpp
@@ -48,7 +48,8 @@ void Attribute::set(ustring name_, TypeDesc type_, AttributeElement element_)
/* string and matrix not supported! */
assert(type == TypeDesc::TypeFloat || type == TypeDesc::TypeColor ||
type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
- type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix || type == TypeFloat2);
+ type == TypeDesc::TypeNormal || type == TypeDesc::TypeMatrix || type == TypeFloat2 ||
+ type == TypeRGBA);
}
void Attribute::resize(Mesh *mesh, AttributePrimitive prim, bool reserve_only)
diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp
index 73893921500..56bf1295446 100644
--- a/intern/cycles/render/bake.cpp
+++ b/intern/cycles/render/bake.cpp
@@ -124,7 +124,7 @@ BakeData *BakeManager::init(const int object, const size_t tri_offset, const siz
void BakeManager::set_shader_limit(const size_t x, const size_t y)
{
m_shader_limit = x * y;
- m_shader_limit = (size_t)pow(2, ceil(log(m_shader_limit) / log(2)));
+ m_shader_limit = (size_t)pow(2, ceilf(logf(m_shader_limit) / logf(2)));
}
bool BakeManager::bake(Device *device,
diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp
index e475ff60eef..fad290c567d 100644
--- a/intern/cycles/render/constant_fold.cpp
+++ b/intern/cycles/render/constant_fold.cpp
@@ -301,95 +301,149 @@ void ConstantFolder::fold_mix(NodeMix type, bool clamp) const
}
}
-void ConstantFolder::fold_math(NodeMath type, bool clamp) const
+void ConstantFolder::fold_math(NodeMathType type) const
{
- ShaderInput *value1_in = node->input("Value1");
- ShaderInput *value2_in = node->input("Value2");
+ ShaderInput *a_in = node->input("A");
+ ShaderInput *b_in = node->input("B");
switch (type) {
case NODE_MATH_ADD:
/* X + 0 == 0 + X == X */
- if (is_zero(value1_in)) {
- try_bypass_or_make_constant(value2_in, clamp);
+ if (is_zero(a_in)) {
+ try_bypass_or_make_constant(b_in);
}
- else if (is_zero(value2_in)) {
- try_bypass_or_make_constant(value1_in, clamp);
+ else if (is_zero(b_in)) {
+ try_bypass_or_make_constant(a_in);
}
break;
case NODE_MATH_SUBTRACT:
/* X - 0 == X */
- if (is_zero(value2_in)) {
- try_bypass_or_make_constant(value1_in, clamp);
+ if (is_zero(b_in)) {
+ try_bypass_or_make_constant(a_in);
}
break;
case NODE_MATH_MULTIPLY:
/* X * 1 == 1 * X == X */
- if (is_one(value1_in)) {
- try_bypass_or_make_constant(value2_in, clamp);
+ if (is_one(a_in)) {
+ try_bypass_or_make_constant(b_in);
}
- else if (is_one(value2_in)) {
- try_bypass_or_make_constant(value1_in, clamp);
+ else if (is_one(b_in)) {
+ try_bypass_or_make_constant(a_in);
}
/* X * 0 == 0 * X == 0 */
- else if (is_zero(value1_in) || is_zero(value2_in)) {
+ else if (is_zero(a_in) || is_zero(b_in)) {
make_zero();
}
break;
case NODE_MATH_DIVIDE:
/* X / 1 == X */
- if (is_one(value2_in)) {
- try_bypass_or_make_constant(value1_in, clamp);
+ if (is_one(b_in)) {
+ try_bypass_or_make_constant(a_in);
}
/* 0 / X == 0 */
- else if (is_zero(value1_in)) {
+ else if (is_zero(a_in)) {
make_zero();
}
break;
case NODE_MATH_POWER:
/* 1 ^ X == X ^ 0 == 1 */
- if (is_one(value1_in) || is_zero(value2_in)) {
+ if (is_one(a_in) || is_zero(b_in)) {
make_one();
}
/* X ^ 1 == X */
- else if (is_one(value2_in)) {
- try_bypass_or_make_constant(value1_in, clamp);
+ else if (is_one(b_in)) {
+ try_bypass_or_make_constant(a_in);
}
default:
break;
}
}
-void ConstantFolder::fold_vector_math(NodeVectorMath type) const
+void ConstantFolder::fold_vector_math(NodeVectorMathType type) const
{
- ShaderInput *vector1_in = node->input("Vector1");
- ShaderInput *vector2_in = node->input("Vector2");
+ ShaderInput *a_in = node->input("A");
+ ShaderInput *b_in = node->input("B");
+ ShaderInput *scale_in = node->input("Scale");
switch (type) {
case NODE_VECTOR_MATH_ADD:
/* X + 0 == 0 + X == X */
- if (is_zero(vector1_in)) {
- try_bypass_or_make_constant(vector2_in);
+ if (is_zero(a_in)) {
+ try_bypass_or_make_constant(b_in);
}
- else if (is_zero(vector2_in)) {
- try_bypass_or_make_constant(vector1_in);
+ else if (is_zero(b_in)) {
+ try_bypass_or_make_constant(a_in);
}
break;
case NODE_VECTOR_MATH_SUBTRACT:
/* X - 0 == X */
- if (is_zero(vector2_in)) {
- try_bypass_or_make_constant(vector1_in);
+ if (is_zero(b_in)) {
+ try_bypass_or_make_constant(a_in);
+ }
+ break;
+ case NODE_VECTOR_MATH_MULTIPLY:
+ /* X * 0 == 0 * X == 0 */
+ if (is_zero(a_in) || is_zero(b_in)) {
+ make_zero();
+ } /* X * 1 == 1 * X == X */
+ else if (is_one(a_in)) {
+ try_bypass_or_make_constant(b_in);
+ }
+ else if (is_one(b_in)) {
+ try_bypass_or_make_constant(a_in);
+ }
+ break;
+ case NODE_VECTOR_MATH_DIVIDE:
+ /* X / 0 == 0 / X == 0 */
+ if (is_zero(a_in) || is_zero(b_in)) {
+ make_zero();
+ } /* X / 1 == X */
+ else if (is_one(b_in)) {
+ try_bypass_or_make_constant(a_in);
}
break;
case NODE_VECTOR_MATH_DOT_PRODUCT:
case NODE_VECTOR_MATH_CROSS_PRODUCT:
/* X * 0 == 0 * X == 0 */
- if (is_zero(vector1_in) || is_zero(vector2_in)) {
+ if (is_zero(a_in) || is_zero(b_in)) {
+ make_zero();
+ }
+ break;
+ case NODE_VECTOR_MATH_LENGTH:
+ case NODE_VECTOR_MATH_ABSOLUTE:
+ if (is_zero(a_in)) {
make_zero();
}
break;
+ case NODE_VECTOR_MATH_SCALE:
+ /* X * 0 == 0 * X == 0 */
+ if (is_zero(a_in) || is_zero(scale_in)) {
+ make_zero();
+ } /* X * 1 == X */
+ else if (is_one(scale_in)) {
+ try_bypass_or_make_constant(a_in);
+ }
+ break;
default:
break;
}
}
+void ConstantFolder::fold_mapping(NodeMappingType type) const
+{
+ ShaderInput *vec_in = node->input("Vector");
+ ShaderInput *loc_in = node->input("Location");
+ ShaderInput *rot_in = node->input("Rotation");
+ ShaderInput *size_in = node->input("Scale");
+
+ if (is_zero(size_in)) {
+ make_zero();
+ }
+ else if ((is_zero(loc_in) || type == NODE_MAPPING_TYPE_VECTOR ||
+ type == NODE_MAPPING_TYPE_NORMAL) &&
+ is_zero(rot_in) && is_one(size_in)) {
+ try_bypass_or_make_constant(vec_in);
+ }
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h
index c14b94868dc..7f622488a88 100644
--- a/intern/cycles/render/constant_fold.h
+++ b/intern/cycles/render/constant_fold.h
@@ -64,8 +64,9 @@ class ConstantFolder {
/* Specific nodes. */
void fold_mix(NodeMix type, bool clamp) const;
- void fold_math(NodeMath type, bool clamp) const;
- void fold_vector_math(NodeVectorMath type) 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/graph.cpp b/intern/cycles/render/graph.cpp
index 501d1e33a9b..eb47ddc5a04 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -1088,16 +1088,16 @@ void ShaderGraph::transform_multi_closure(ShaderNode *node, ShaderOutput *weight
add(math_node);
if (weight_in->link)
- connect(weight_in->link, math_node->input("Value1"));
+ connect(weight_in->link, math_node->input("A"));
else
- math_node->value1 = weight_value;
+ math_node->a = weight_value;
if (weight_out)
- connect(weight_out, math_node->input("Value2"));
+ connect(weight_out, math_node->input("B"));
else
- math_node->value2 = 1.0f;
+ math_node->b = 1.0f;
- weight_out = math_node->output("Value");
+ weight_out = math_node->output("Result");
if (weight_in->link)
disconnect(weight_in);
}
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index 76258a292e8..82020db5b60 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -141,7 +141,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene
kintegrator->caustics_refractive = caustics_refractive;
kintegrator->filter_glossy = (filter_glossy == 0.0f) ? FLT_MAX : 1.0f / filter_glossy;
- kintegrator->seed = hash_int(seed);
+ kintegrator->seed = hash_uint(seed);
kintegrator->use_ambient_occlusion = ((Pass::contains(scene->film->passes, PASS_AO)) ||
dscene->data.background.ao_factor != 0.0f);
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 91c3a772537..e13ed97e771 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -1201,6 +1201,8 @@ void MeshManager::update_osl_attributes(Device *device,
osl_attr.type = TypeDesc::TypeMatrix;
else if (req.triangle_type == TypeFloat2)
osl_attr.type = TypeFloat2;
+ else if (req.triangle_type == TypeRGBA)
+ osl_attr.type = TypeRGBA;
else
osl_attr.type = TypeDesc::TypeColor;
@@ -1224,6 +1226,8 @@ void MeshManager::update_osl_attributes(Device *device,
osl_attr.type = TypeDesc::TypeMatrix;
else if (req.curve_type == TypeFloat2)
osl_attr.type = TypeFloat2;
+ else if (req.curve_type == TypeRGBA)
+ osl_attr.type = TypeRGBA;
else
osl_attr.type = TypeDesc::TypeColor;
@@ -1247,6 +1251,8 @@ void MeshManager::update_osl_attributes(Device *device,
osl_attr.type = TypeDesc::TypeMatrix;
else if (req.subd_type == TypeFloat2)
osl_attr.type = TypeFloat2;
+ else if (req.subd_type == TypeRGBA)
+ osl_attr.type = TypeRGBA;
else
osl_attr.type = TypeDesc::TypeColor;
@@ -1319,6 +1325,8 @@ void MeshManager::update_svm_attributes(Device *,
attr_map[index].w = NODE_ATTR_MATRIX;
else if (req.triangle_type == TypeFloat2)
attr_map[index].w = NODE_ATTR_FLOAT2;
+ else if (req.triangle_type == TypeRGBA)
+ attr_map[index].w = NODE_ATTR_RGBA;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
@@ -1357,6 +1365,8 @@ void MeshManager::update_svm_attributes(Device *,
attr_map[index].w = NODE_ATTR_MATRIX;
else if (req.subd_type == TypeFloat2)
attr_map[index].w = NODE_ATTR_FLOAT2;
+ else if (req.triangle_type == TypeRGBA)
+ attr_map[index].w = NODE_ATTR_RGBA;
else
attr_map[index].w = NODE_ATTR_FLOAT3;
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp
index 8e7969cfbaf..2dc9371c5d1 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);
@@ -164,7 +165,7 @@ void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_ou
if (type == NORMAL) {
compiler.add_node(NODE_VECTOR_MATH, NODE_VECTOR_MATH_NORMALIZE, offset_out, offset_out);
- compiler.add_node(NODE_VECTOR_MATH, SVM_STACK_INVALID, offset_out);
+ compiler.add_node(NODE_VECTOR_MATH, offset_out, SVM_STACK_INVALID, offset_out);
}
}
@@ -891,14 +892,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_FLOAT(value, "Value");
SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(fac, "Fac");
return type;
}
@@ -909,23 +918,30 @@ 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");
+ ShaderInput *w_in = input("W");
+ ShaderInput *scale_in = input("Scale");
+ ShaderInput *detail_in = input("Detail");
+ ShaderInput *distortion_in = input("Distortion");
+
+ ShaderOutput *value_out = output("Value");
ShaderOutput *color_out = output("Color");
- ShaderOutput *fac_out = output("Fac");
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_NOISE,
+ dimensions,
compiler.encode_uchar4(vector_offset,
+ compiler.stack_assign_if_linked(w_in),
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.stack_assign_if_linked(detail_in)),
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(distortion_in),
+ compiler.stack_assign_if_linked(value_out),
+ compiler.stack_assign_if_linked(color_out)));
+ 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);
}
@@ -933,7 +949,7 @@ void NoiseTextureNode::compile(SVMCompiler &compiler)
void NoiseTextureNode::compile(OSLCompiler &compiler)
{
tex_mapping.compile(compiler);
-
+ compiler.parameter(this, "dimensions");
compiler.add(this, "node_noise_texture");
}
@@ -945,33 +961,41 @@ NODE_DEFINE(VoronoiTextureNode)
TEXTURE_MAPPING_DEFINE(VoronoiTextureNode);
- static NodeEnum coloring_enum;
- coloring_enum.insert("intensity", NODE_VORONOI_INTENSITY);
- coloring_enum.insert("cells", NODE_VORONOI_CELLS);
- SOCKET_ENUM(coloring, "Coloring", coloring_enum, NODE_VORONOI_INTENSITY);
+ 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);
- static NodeEnum metric;
- metric.insert("distance", NODE_VORONOI_DISTANCE);
- metric.insert("manhattan", NODE_VORONOI_MANHATTAN);
- metric.insert("chebychev", NODE_VORONOI_CHEBYCHEV);
- metric.insert("minkowski", NODE_VORONOI_MINKOWSKI);
- SOCKET_ENUM(metric, "Distance Metric", metric, NODE_VORONOI_INTENSITY);
+ static NodeEnum metric_enum;
+ metric_enum.insert("euclidean", NODE_VORONOI_EUCLIDEAN);
+ metric_enum.insert("manhattan", NODE_VORONOI_MANHATTAN);
+ metric_enum.insert("chebychev", NODE_VORONOI_CHEBYCHEV);
+ metric_enum.insert("minkowski", NODE_VORONOI_MINKOWSKI);
+ SOCKET_ENUM(metric, "Distance Metric", metric_enum, NODE_VORONOI_EUCLIDEAN);
static NodeEnum feature_enum;
- feature_enum.insert("F1", NODE_VORONOI_F1);
- feature_enum.insert("F2", NODE_VORONOI_F2);
- feature_enum.insert("F3", NODE_VORONOI_F3);
- feature_enum.insert("F4", NODE_VORONOI_F4);
- feature_enum.insert("F2F1", NODE_VORONOI_F2F1);
- SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_INTENSITY);
+ feature_enum.insert("f1", NODE_VORONOI_F1);
+ feature_enum.insert("smooth_f1", NODE_VORONOI_SMOOTH_F1);
+ feature_enum.insert("f2", NODE_VORONOI_F2);
+ feature_enum.insert("distance_to_edge", NODE_VORONOI_DISTANCE_TO_EDGE);
+ feature_enum.insert("n_sphere_radius", NODE_VORONOI_N_SPHERE_RADIUS);
+ SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_F1);
- SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
- SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
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", 5.0f);
+ SOCKET_IN_FLOAT(smoothness, "Smoothness", 5.0f);
+ SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
+ SOCKET_IN_FLOAT(jitter, "Jitter", 1.0f);
+ SOCKET_OUT_FLOAT(distance, "Distance");
SOCKET_OUT_COLOR(color, "Color");
- SOCKET_OUT_FLOAT(fac, "Fac");
+ SOCKET_OUT_POINT(position, "Position");
+ SOCKET_OUT_FLOAT(w, "W");
+ SOCKET_OUT_FLOAT(radius, "Radius");
return type;
}
@@ -982,28 +1006,39 @@ VoronoiTextureNode::VoronoiTextureNode() : TextureNode(node_type)
void VoronoiTextureNode::compile(SVMCompiler &compiler)
{
- ShaderInput *scale_in = input("Scale");
ShaderInput *vector_in = input("Vector");
+ ShaderInput *w_in = input("W");
+ ShaderInput *scale_in = input("Scale");
+ ShaderInput *smoothness_in = input("Smoothness");
ShaderInput *exponent_in = input("Exponent");
- ShaderOutput *color_out = output("Color");
- ShaderOutput *fac_out = output("Fac");
+ ShaderInput *jitter_in = input("Jitter");
- if (vector_in->link)
- compiler.stack_assign(vector_in);
- if (scale_in->link)
- compiler.stack_assign(scale_in);
- if (exponent_in->link)
- compiler.stack_assign(exponent_in);
+ ShaderOutput *distance_out = output("Distance");
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *position_out = output("Position");
+ ShaderOutput *w_out = output("W");
+ ShaderOutput *radius_out = output("Radius");
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
- compiler.add_node(NODE_TEX_VORONOI,
- compiler.encode_uchar4(vector_offset, coloring, metric, feature),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(scale_in),
- compiler.stack_assign_if_linked(exponent_in),
- compiler.stack_assign(fac_out),
- compiler.stack_assign(color_out)));
- compiler.add_node(__float_as_int(scale), __float_as_int(exponent));
+ compiler.add_node(NODE_TEX_VORONOI, dimensions, feature, metric);
+ compiler.add_node(compiler.encode_uchar4(vector_offset,
+ compiler.stack_assign_if_linked(w_in),
+ compiler.stack_assign_if_linked(scale_in),
+ compiler.stack_assign_if_linked(smoothness_in)),
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(exponent_in),
+ compiler.stack_assign_if_linked(jitter_in),
+ compiler.stack_assign_if_linked(distance_out),
+ compiler.stack_assign_if_linked(color_out)),
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(position_out),
+ compiler.stack_assign_if_linked(w_out),
+ compiler.stack_assign_if_linked(radius_out)),
+ __float_as_int(w));
+
+ compiler.add_node(__float_as_int(scale),
+ __float_as_int(smoothness),
+ __float_as_int(exponent),
+ __float_as_int(jitter));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1012,9 +1047,9 @@ void VoronoiTextureNode::compile(OSLCompiler &compiler)
{
tex_mapping.compile(compiler);
- compiler.parameter(this, "coloring");
- compiler.parameter(this, "metric");
+ compiler.parameter(this, "dimensions");
compiler.parameter(this, "feature");
+ compiler.parameter(this, "metric");
compiler.add(this, "node_voronoi_texture");
}
@@ -1108,6 +1143,50 @@ void IESLightNode::compile(OSLCompiler &compiler)
compiler.add(this, "node_ies_light");
}
+/* White Noise Texture */
+
+NODE_DEFINE(WhiteNoiseTextureNode)
+{
+ NodeType *type = NodeType::add("white_noise_texture", create, NodeType::SHADER);
+
+ 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));
+ SOCKET_IN_FLOAT(w, "W", 0.0f);
+
+ SOCKET_OUT_FLOAT(value, "Value");
+
+ return type;
+}
+
+WhiteNoiseTextureNode::WhiteNoiseTextureNode() : ShaderNode(node_type)
+{
+}
+
+void WhiteNoiseTextureNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *vector_in = input("Vector");
+ ShaderInput *w_in = input("W");
+ ShaderOutput *value_out = output("Value");
+
+ compiler.add_node(NODE_TEX_WHITE_NOISE,
+ dimensions,
+ compiler.stack_assign(vector_in),
+ compiler.stack_assign(w_in));
+ compiler.add_node(NODE_TEX_WHITE_NOISE, compiler.stack_assign(value_out));
+}
+
+void WhiteNoiseTextureNode::compile(OSLCompiler &compiler)
+{
+ compiler.parameter(this, "dimensions");
+ compiler.add(this, "node_white_noise_texture");
+}
+
/* Musgrave Texture */
NODE_DEFINE(MusgraveTextureNode)
@@ -1116,6 +1195,13 @@ NODE_DEFINE(MusgraveTextureNode)
TEXTURE_MAPPING_DEFINE(MusgraveTextureNode);
+ 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);
+
static NodeEnum type_enum;
type_enum.insert("multifractal", NODE_MUSGRAVE_MULTIFRACTAL);
type_enum.insert("fBM", NODE_MUSGRAVE_FBM);
@@ -1124,16 +1210,16 @@ NODE_DEFINE(MusgraveTextureNode)
type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN);
SOCKET_ENUM(type, "Type", type_enum, NODE_MUSGRAVE_FBM);
+ 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(dimension, "Dimension", 2.0f);
SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 1.0f);
SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
SOCKET_IN_FLOAT(gain, "Gain", 1.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");
return type;
@@ -1146,33 +1232,31 @@ MusgraveTextureNode::MusgraveTextureNode() : TextureNode(node_type)
void MusgraveTextureNode::compile(SVMCompiler &compiler)
{
ShaderInput *vector_in = input("Vector");
+ ShaderInput *w_in = input("W");
ShaderInput *scale_in = input("Scale");
+ ShaderInput *detail_in = input("Detail");
ShaderInput *dimension_in = input("Dimension");
ShaderInput *lacunarity_in = input("Lacunarity");
- ShaderInput *detail_in = input("Detail");
ShaderInput *offset_in = input("Offset");
ShaderInput *gain_in = input("Gain");
+
ShaderOutput *fac_out = output("Fac");
- ShaderOutput *color_out = output("Color");
int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
compiler.add_node(NODE_TEX_MUSGRAVE,
- compiler.encode_uchar4(type,
- vector_offset,
- compiler.stack_assign_if_linked(color_out),
- compiler.stack_assign_if_linked(fac_out)),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(dimension_in),
- compiler.stack_assign_if_linked(lacunarity_in),
+ compiler.encode_uchar4(
+ type, dimensions, vector_offset, compiler.stack_assign_if_linked(w_in)),
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(scale_in),
compiler.stack_assign_if_linked(detail_in),
- compiler.stack_assign_if_linked(offset_in)),
- compiler.encode_uchar4(compiler.stack_assign_if_linked(gain_in),
- compiler.stack_assign_if_linked(scale_in)));
- compiler.add_node(__float_as_int(dimension),
- __float_as_int(lacunarity),
- __float_as_int(detail),
- __float_as_int(offset));
- compiler.add_node(__float_as_int(gain), __float_as_int(scale));
+ compiler.stack_assign_if_linked(dimension_in),
+ compiler.stack_assign_if_linked(lacunarity_in)),
+ compiler.encode_uchar4(compiler.stack_assign_if_linked(offset_in),
+ compiler.stack_assign_if_linked(gain_in),
+ compiler.stack_assign_if_linked(fac_out)));
+ compiler.add_node(
+ __float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(dimension));
+ compiler.add_node(__float_as_int(lacunarity), __float_as_int(offset), __float_as_int(gain));
tex_mapping.compile_end(compiler, vector_in, vector_offset);
}
@@ -1182,6 +1266,7 @@ void MusgraveTextureNode::compile(OSLCompiler &compiler)
tex_mapping.compile(compiler);
compiler.parameter(this, "type");
+ compiler.parameter(this, "dimensions");
compiler.add(this, "node_musgrave_texture");
}
@@ -1661,10 +1746,19 @@ 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_OUT_POINT(vector, "Vector");
+ 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(result, "Result");
return type;
}
@@ -1673,22 +1767,37 @@ 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");
- ShaderOutput *vector_out = output("Vector");
+ ShaderInput *location_in = input("Location");
+ ShaderInput *rotation_in = input("Rotation");
+ ShaderInput *scale_in = input("Scale");
+
+ ShaderOutput *result_out = output("Result");
+
+ int rotation_stack = compiler.stack_assign(rotation_in);
+ int scale_stack = compiler.stack_assign(scale_in);
- tex_mapping.compile(
- compiler, compiler.stack_assign(vector_in), compiler.stack_assign(vector_out));
+ compiler.add_node(
+ NODE_MAPPING, type, compiler.stack_assign(vector_in), compiler.stack_assign(location_in));
+ compiler.add_node(NODE_MAPPING, rotation_stack, scale_stack, compiler.stack_assign(result_out));
}
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");
}
@@ -3891,6 +4000,7 @@ NODE_DEFINE(ObjectInfoNode)
NodeType *type = NodeType::add("object_info", create, NodeType::SHADER);
SOCKET_OUT_VECTOR(location, "Location");
+ SOCKET_OUT_COLOR(color, "Color");
SOCKET_OUT_FLOAT(object_index, "Object Index");
SOCKET_OUT_FLOAT(material_index, "Material Index");
SOCKET_OUT_FLOAT(random, "Random");
@@ -3909,6 +4019,11 @@ void ObjectInfoNode::compile(SVMCompiler &compiler)
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_LOCATION, compiler.stack_assign(out));
}
+ out = output("Color");
+ if (!out->links.empty()) {
+ compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_COLOR, compiler.stack_assign(out));
+ }
+
out = output("Object Index");
if (!out->links.empty()) {
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_INDEX, compiler.stack_assign(out));
@@ -4119,6 +4234,148 @@ void HairInfoNode::compile(OSLCompiler &compiler)
compiler.add(this, "node_hair_info");
}
+/* Volume Info */
+
+NODE_DEFINE(VolumeInfoNode)
+{
+ NodeType *type = NodeType::add("volume_info", create, NodeType::SHADER);
+
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(density, "Density");
+ SOCKET_OUT_FLOAT(flame, "Flame");
+ SOCKET_OUT_FLOAT(temperature, "Temperature");
+
+ return type;
+}
+
+VolumeInfoNode::VolumeInfoNode() : ShaderNode(node_type)
+{
+}
+
+/* The requested attributes are not updated after node expansion.
+ * So we explicitly request the required attributes.
+ */
+void VolumeInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (shader->has_volume) {
+ if (!output("Color")->links.empty()) {
+ attributes->add(ATTR_STD_VOLUME_COLOR);
+ }
+ if (!output("Density")->links.empty()) {
+ attributes->add(ATTR_STD_VOLUME_DENSITY);
+ }
+ if (!output("Flame")->links.empty()) {
+ attributes->add(ATTR_STD_VOLUME_FLAME);
+ }
+ if (!output("Temperature")->links.empty()) {
+ attributes->add(ATTR_STD_VOLUME_TEMPERATURE);
+ }
+ attributes->add(ATTR_STD_GENERATED_TRANSFORM);
+ }
+ ShaderNode::attributes(shader, attributes);
+}
+
+void VolumeInfoNode::expand(ShaderGraph *graph)
+{
+ ShaderOutput *color_out = output("Color");
+ if (!color_out->links.empty()) {
+ AttributeNode *attr = new AttributeNode();
+ attr->attribute = "color";
+ graph->add(attr);
+ graph->relink(color_out, attr->output("Color"));
+ }
+
+ ShaderOutput *density_out = output("Density");
+ if (!density_out->links.empty()) {
+ AttributeNode *attr = new AttributeNode();
+ attr->attribute = "density";
+ graph->add(attr);
+ graph->relink(density_out, attr->output("Fac"));
+ }
+
+ ShaderOutput *flame_out = output("Flame");
+ if (!flame_out->links.empty()) {
+ AttributeNode *attr = new AttributeNode();
+ attr->attribute = "flame";
+ graph->add(attr);
+ graph->relink(flame_out, attr->output("Fac"));
+ }
+
+ ShaderOutput *temperature_out = output("Temperature");
+ if (!temperature_out->links.empty()) {
+ AttributeNode *attr = new AttributeNode();
+ attr->attribute = "temperature";
+ graph->add(attr);
+ graph->relink(temperature_out, attr->output("Fac"));
+ }
+}
+
+void VolumeInfoNode::compile(SVMCompiler &)
+{
+}
+
+void VolumeInfoNode::compile(OSLCompiler &)
+{
+}
+
+NODE_DEFINE(VertexColorNode)
+{
+ NodeType *type = NodeType::add("vertex_color", create, NodeType::SHADER);
+
+ SOCKET_STRING(layer_name, "Layer Name", ustring());
+ SOCKET_OUT_COLOR(color, "Color");
+ SOCKET_OUT_FLOAT(alpha, "Alpha");
+
+ return type;
+}
+
+VertexColorNode::VertexColorNode() : ShaderNode(node_type)
+{
+}
+
+void VertexColorNode::attributes(Shader *shader, AttributeRequestSet *attributes)
+{
+ if (!(output("Color")->links.empty() && output("Alpha")->links.empty())) {
+ attributes->add_standard(layer_name);
+ }
+ ShaderNode::attributes(shader, attributes);
+}
+
+void VertexColorNode::compile(SVMCompiler &compiler)
+{
+ ShaderOutput *color_out = output("Color");
+ ShaderOutput *alpha_out = output("Alpha");
+ int layer_id = compiler.attribute(layer_name);
+
+ ShaderNodeType node;
+
+ if (bump == SHADER_BUMP_DX)
+ node = NODE_VERTEX_COLOR_BUMP_DX;
+ else if (bump == SHADER_BUMP_DY)
+ node = NODE_VERTEX_COLOR_BUMP_DY;
+ else {
+ node = NODE_VERTEX_COLOR;
+ }
+
+ compiler.add_node(
+ node, layer_id, compiler.stack_assign(color_out), compiler.stack_assign(alpha_out));
+}
+
+void VertexColorNode::compile(OSLCompiler &compiler)
+{
+ if (bump == SHADER_BUMP_DX) {
+ compiler.parameter("bump_offset", "dx");
+ }
+ else if (bump == SHADER_BUMP_DY) {
+ compiler.parameter("bump_offset", "dy");
+ }
+ else {
+ compiler.parameter("bump_offset", "center");
+ }
+ compiler.parameter("layer_name", layer_name.c_str());
+ compiler.add(this, "node_vertex_color");
+}
+
/* Value */
NODE_DEFINE(ValueNode)
@@ -5259,6 +5516,112 @@ void OutputNode::compile(OSLCompiler &compiler)
compiler.add(this, "node_output_displacement");
}
+/* Map Range Node */
+
+NODE_DEFINE(MapRangeNode)
+{
+ NodeType *type = NodeType::add("map_range", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(value, "Value", 1.0f);
+ SOCKET_IN_FLOAT(fromMin, "From Min", 0.0f);
+ SOCKET_IN_FLOAT(fromMax, "From Max", 1.0f);
+ SOCKET_IN_FLOAT(toMin, "To Min", 0.0f);
+ SOCKET_IN_FLOAT(toMax, "To Max", 1.0f);
+
+ SOCKET_OUT_FLOAT(result, "Result");
+
+ return type;
+}
+
+MapRangeNode::MapRangeNode() : ShaderNode(node_type)
+{
+}
+
+void MapRangeNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ float result;
+ if (fromMax != fromMin) {
+ result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
+ }
+ else {
+ result = 0.0f;
+ }
+ folder.make_constant(result);
+ }
+}
+
+void MapRangeNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *value_in = input("Value");
+ ShaderInput *fromMin_in = input("From Min");
+ ShaderInput *fromMax_in = input("From Max");
+ ShaderInput *toMin_in = input("To Min");
+ ShaderInput *toMax_in = input("To Max");
+
+ ShaderOutput *result_out = output("Result");
+
+ int toMin_stack = compiler.stack_assign(toMin_in);
+ int toMax_stack = compiler.stack_assign(toMax_in);
+
+ compiler.add_node(NODE_MAP_RANGE,
+ compiler.stack_assign(value_in),
+ compiler.stack_assign(fromMin_in),
+ compiler.stack_assign(fromMax_in));
+ compiler.add_node(NODE_MAP_RANGE, toMin_stack, toMax_stack, compiler.stack_assign(result_out));
+}
+
+void MapRangeNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_map_range");
+}
+
+/* Clamp Node */
+
+NODE_DEFINE(ClampNode)
+{
+ NodeType *type = NodeType::add("clamp", create, NodeType::SHADER);
+
+ SOCKET_IN_FLOAT(value, "Value", 1.0f);
+ SOCKET_IN_FLOAT(min, "Min", 0.0f);
+ SOCKET_IN_FLOAT(max, "Max", 1.0f);
+
+ SOCKET_OUT_FLOAT(result, "Result");
+
+ return type;
+}
+
+ClampNode::ClampNode() : ShaderNode(node_type)
+{
+}
+
+void ClampNode::constant_fold(const ConstantFolder &folder)
+{
+ if (folder.all_inputs_constant()) {
+ folder.make_constant(clamp(value, min, max));
+ }
+}
+
+void ClampNode::compile(SVMCompiler &compiler)
+{
+ ShaderInput *value_in = input("Value");
+ ShaderInput *min_in = input("Min");
+ ShaderInput *max_in = input("Max");
+
+ ShaderOutput *result_out = output("Result");
+
+ compiler.add_node(NODE_CLAMP,
+ compiler.stack_assign(value_in),
+ compiler.stack_assign(min_in),
+ compiler.stack_assign(max_in));
+ compiler.add_node(NODE_CLAMP, compiler.stack_assign(result_out));
+}
+
+void ClampNode::compile(OSLCompiler &compiler)
+{
+ compiler.add(this, "node_clamp");
+}
+
/* Math */
NODE_DEFINE(MathNode)
@@ -5270,34 +5633,36 @@ NODE_DEFINE(MathNode)
type_enum.insert("subtract", NODE_MATH_SUBTRACT);
type_enum.insert("multiply", NODE_MATH_MULTIPLY);
type_enum.insert("divide", NODE_MATH_DIVIDE);
- type_enum.insert("sine", NODE_MATH_SINE);
- type_enum.insert("cosine", NODE_MATH_COSINE);
- type_enum.insert("tangent", NODE_MATH_TANGENT);
- type_enum.insert("arcsine", NODE_MATH_ARCSINE);
- type_enum.insert("arccosine", NODE_MATH_ARCCOSINE);
- type_enum.insert("arctangent", NODE_MATH_ARCTANGENT);
+
type_enum.insert("power", NODE_MATH_POWER);
type_enum.insert("logarithm", NODE_MATH_LOGARITHM);
+ type_enum.insert("sqrt", NODE_MATH_SQRT);
+ type_enum.insert("absolute", NODE_MATH_ABSOLUTE);
+
type_enum.insert("minimum", NODE_MATH_MINIMUM);
type_enum.insert("maximum", NODE_MATH_MAXIMUM);
- type_enum.insert("round", NODE_MATH_ROUND);
type_enum.insert("less_than", NODE_MATH_LESS_THAN);
type_enum.insert("greater_than", NODE_MATH_GREATER_THAN);
- type_enum.insert("modulo", NODE_MATH_MODULO);
- type_enum.insert("absolute", NODE_MATH_ABSOLUTE);
- type_enum.insert("arctan2", NODE_MATH_ARCTAN2);
+
+ type_enum.insert("round", NODE_MATH_ROUND);
type_enum.insert("floor", NODE_MATH_FLOOR);
type_enum.insert("ceil", NODE_MATH_CEIL);
- type_enum.insert("fract", NODE_MATH_FRACT);
- type_enum.insert("sqrt", NODE_MATH_SQRT);
- SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD);
+ type_enum.insert("fraction", NODE_MATH_FRACTION);
+ type_enum.insert("modulo", NODE_MATH_MODULO);
- SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
+ type_enum.insert("sine", NODE_MATH_SINE);
+ type_enum.insert("cosine", NODE_MATH_COSINE);
+ type_enum.insert("tangent", NODE_MATH_TANGENT);
+ type_enum.insert("arcsine", NODE_MATH_ARCSINE);
+ type_enum.insert("arccosine", NODE_MATH_ARCCOSINE);
+ type_enum.insert("arctangent", NODE_MATH_ARCTANGENT);
+ type_enum.insert("arctan2", NODE_MATH_ARCTAN2);
+ SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD);
- SOCKET_IN_FLOAT(value1, "Value1", 0.0f);
- SOCKET_IN_FLOAT(value2, "Value2", 0.0f);
+ SOCKET_IN_FLOAT(a, "A", 0.5f);
+ SOCKET_IN_FLOAT(b, "B", 0.5f);
- SOCKET_OUT_FLOAT(value, "Value");
+ SOCKET_OUT_FLOAT(result, "Result");
return type;
}
@@ -5309,33 +5674,26 @@ MathNode::MathNode() : ShaderNode(node_type)
void MathNode::constant_fold(const ConstantFolder &folder)
{
if (folder.all_inputs_constant()) {
- folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp);
+ folder.make_constant(svm_math(type, a, b));
}
else {
- folder.fold_math(type, use_clamp);
+ folder.fold_math(type);
}
}
void MathNode::compile(SVMCompiler &compiler)
{
- ShaderInput *value1_in = input("Value1");
- ShaderInput *value2_in = input("Value2");
- ShaderOutput *value_out = output("Value");
-
- compiler.add_node(
- NODE_MATH, type, compiler.stack_assign(value1_in), compiler.stack_assign(value2_in));
- compiler.add_node(NODE_MATH, compiler.stack_assign(value_out));
+ ShaderInput *a_in = input("A");
+ ShaderInput *b_in = input("B");
+ ShaderOutput *result_out = output("Result");
- if (use_clamp) {
- compiler.add_node(NODE_MATH, NODE_MATH_CLAMP, compiler.stack_assign(value_out));
- compiler.add_node(NODE_MATH, compiler.stack_assign(value_out));
- }
+ compiler.add_node(NODE_MATH, type, compiler.stack_assign(a_in), compiler.stack_assign(b_in));
+ compiler.add_node(NODE_MATH, compiler.stack_assign(result_out));
}
void MathNode::compile(OSLCompiler &compiler)
{
compiler.parameter(this, "type");
- compiler.parameter(this, "use_clamp");
compiler.add(this, "node_math");
}
@@ -5348,14 +5706,32 @@ NODE_DEFINE(VectorMathNode)
static NodeEnum type_enum;
type_enum.insert("add", NODE_VECTOR_MATH_ADD);
type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT);
- type_enum.insert("average", NODE_VECTOR_MATH_AVERAGE);
- type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT);
+ type_enum.insert("multiply", NODE_VECTOR_MATH_MULTIPLY);
+ type_enum.insert("divide", NODE_VECTOR_MATH_DIVIDE);
+
type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT);
+ type_enum.insert("project", NODE_VECTOR_MATH_PROJECT);
+ type_enum.insert("reflect", NODE_VECTOR_MATH_REFLECT);
+ type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT);
+
+ type_enum.insert("distance", NODE_VECTOR_MATH_DISTANCE);
+ type_enum.insert("length", NODE_VECTOR_MATH_LENGTH);
+ type_enum.insert("scale", NODE_VECTOR_MATH_SCALE);
type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE);
+
+ type_enum.insert("snap", NODE_VECTOR_MATH_SNAP);
+ type_enum.insert("floor", NODE_VECTOR_MATH_FLOOR);
+ type_enum.insert("ceil", NODE_VECTOR_MATH_CEIL);
+ type_enum.insert("modulo", NODE_VECTOR_MATH_MODULO);
+ type_enum.insert("fraction", NODE_VECTOR_MATH_FRACTION);
+ type_enum.insert("absolute", NODE_VECTOR_MATH_ABSOLUTE);
+ type_enum.insert("minimum", NODE_VECTOR_MATH_MINIMUM);
+ type_enum.insert("maximum", NODE_VECTOR_MATH_MAXIMUM);
SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_MATH_ADD);
- SOCKET_IN_VECTOR(vector1, "Vector1", make_float3(0.0f, 0.0f, 0.0f));
- SOCKET_IN_VECTOR(vector2, "Vector2", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_VECTOR(a, "A", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_VECTOR(b, "B", make_float3(0.0f, 0.0f, 0.0f));
+ SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
SOCKET_OUT_FLOAT(value, "Value");
SOCKET_OUT_VECTOR(vector, "Vector");
@@ -5373,8 +5749,7 @@ void VectorMathNode::constant_fold(const ConstantFolder &folder)
float3 vector;
if (folder.all_inputs_constant()) {
- svm_vector_math(&value, &vector, type, vector1, vector2);
-
+ svm_vector_math(&value, &vector, type, a, b, scale);
if (folder.output == output("Value")) {
folder.make_constant(value);
}
@@ -5389,17 +5764,21 @@ void VectorMathNode::constant_fold(const ConstantFolder &folder)
void VectorMathNode::compile(SVMCompiler &compiler)
{
- ShaderInput *vector1_in = input("Vector1");
- ShaderInput *vector2_in = input("Vector2");
+ ShaderInput *a_in = input("A");
+ ShaderInput *b_in = input("B");
+ ShaderInput *scale_in = input("Scale");
+
ShaderOutput *value_out = output("Value");
ShaderOutput *vector_out = output("Vector");
- compiler.add_node(NODE_VECTOR_MATH,
- type,
- compiler.stack_assign(vector1_in),
- compiler.stack_assign(vector2_in));
+ int scale_stack = compiler.stack_assign(scale_in);
+
compiler.add_node(
- NODE_VECTOR_MATH, compiler.stack_assign(value_out), compiler.stack_assign(vector_out));
+ NODE_VECTOR_MATH, type, compiler.stack_assign(a_in), compiler.stack_assign(b_in));
+ compiler.add_node(NODE_VECTOR_MATH,
+ scale_stack,
+ compiler.stack_assign_if_linked(value_out),
+ compiler.stack_assign_if_linked(vector_out));
}
void VectorMathNode::compile(OSLCompiler &compiler)
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index 6b21be88663..1a83d68c156 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;
};
@@ -219,10 +220,10 @@ class VoronoiTextureNode : public TextureNode {
return NODE_GROUP_LEVEL_2;
}
- NodeVoronoiColoring coloring;
+ int dimensions;
NodeVoronoiDistanceMetric metric;
NodeVoronoiFeature feature;
- float scale, exponent;
+ float w, scale, exponent, smoothness, jitter;
float3 vector;
};
@@ -235,8 +236,9 @@ class MusgraveTextureNode : public TextureNode {
return NODE_GROUP_LEVEL_2;
}
+ int dimensions;
NodeMusgraveType type;
- float scale, detail, dimension, lacunarity, offset, gain;
+ float w, scale, detail, dimension, lacunarity, offset, gain;
float3 vector;
};
@@ -300,6 +302,19 @@ class BrickTextureNode : public TextureNode {
}
};
+class WhiteNoiseTextureNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(WhiteNoiseTextureNode)
+ virtual int get_group()
+ {
+ return NODE_GROUP_LEVEL_2;
+ }
+
+ int dimensions;
+ float3 vector;
+ float w;
+};
+
class PointDensityTextureNode : public ShaderNode {
public:
SHADER_NODE_NO_CLONE_CLASS(PointDensityTextureNode)
@@ -377,9 +392,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 {
@@ -948,6 +964,37 @@ class HairInfoNode : public ShaderNode {
}
};
+class VolumeInfoNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(VolumeInfoNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+ void expand(ShaderGraph *graph);
+};
+
+class VertexColorNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(VertexColorNode)
+ void attributes(Shader *shader, AttributeRequestSet *attributes);
+ bool has_attribute_dependency()
+ {
+ return true;
+ }
+ bool has_spatial_varying()
+ {
+ return true;
+ }
+
+ ustring layer_name;
+};
+
class ValueNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ValueNode)
@@ -1228,6 +1275,28 @@ class BlackbodyNode : public ShaderNode {
float temperature;
};
+class MapRangeNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(MapRangeNode)
+ void constant_fold(const ConstantFolder &folder);
+ virtual int get_group()
+ {
+ return NODE_GROUP_LEVEL_3;
+ }
+ float value, fromMin, fromMax, toMin, toMax;
+};
+
+class ClampNode : public ShaderNode {
+ public:
+ SHADER_NODE_CLASS(ClampNode)
+ void constant_fold(const ConstantFolder &folder);
+ virtual int get_group()
+ {
+ return NODE_GROUP_LEVEL_3;
+ }
+ float value, min, max;
+};
+
class MathNode : public ShaderNode {
public:
SHADER_NODE_CLASS(MathNode)
@@ -1237,10 +1306,9 @@ class MathNode : public ShaderNode {
}
void constant_fold(const ConstantFolder &folder);
- float value1;
- float value2;
- NodeMath type;
- bool use_clamp;
+ float a;
+ float b;
+ NodeMathType type;
};
class NormalNode : public ShaderNode {
@@ -1264,9 +1332,10 @@ class VectorMathNode : public ShaderNode {
}
void constant_fold(const ConstantFolder &folder);
- float3 vector1;
- float3 vector2;
- NodeVectorMath type;
+ float3 a;
+ float3 b;
+ float scale;
+ NodeVectorMathType type;
};
class VectorTransformNode : public ShaderNode {
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index 6c6f8810412..849329a086d 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -90,6 +90,7 @@ NODE_DEFINE(Object)
SOCKET_NODE(mesh, "Mesh", &Mesh::node_type);
SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
SOCKET_UINT(visibility, "Visibility", ~0);
+ SOCKET_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_UINT(random_id, "Random ID", 0);
SOCKET_INT(pass_id, "Pass ID", 0);
SOCKET_BOOLEAN(use_holdout, "Use Holdout", false);
@@ -371,6 +372,7 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
*/
float uniform_scale;
float surface_area = 0.0f;
+ float3 color = ob->color;
float pass_id = ob->pass_id;
float random_number = (float)ob->random_id * (1.0f / (float)0xFFFFFFFF);
int particle_index = (ob->particle_system) ?
@@ -425,6 +427,9 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s
kobject.tfm = tfm;
kobject.itfm = itfm;
kobject.surface_area = surface_area;
+ kobject.color[0] = color.x;
+ kobject.color[1] = color.y;
+ kobject.color[2] = color.z;
kobject.pass_id = pass_id;
kobject.random_number = random_number;
kobject.particle_index = particle_index;
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
index 2fd43900da1..cbbff0d4c6d 100644
--- a/intern/cycles/render/object.h
+++ b/intern/cycles/render/object.h
@@ -51,6 +51,7 @@ class Object : public Node {
BoundBox bounds;
uint random_id;
int pass_id;
+ float3 color;
ustring asset_name;
vector<ParamValue> attributes;
uint visibility;
diff --git a/intern/cycles/subd/subd_dice.cpp b/intern/cycles/subd/subd_dice.cpp
index fb96be5065b..914b408911e 100644
--- a/intern/cycles/subd/subd_dice.cpp
+++ b/intern/cycles/subd/subd_dice.cpp
@@ -323,8 +323,8 @@ void QuadDice::dice(SubPatch &sub, EdgeFactors &ef)
float S = 1.0f;
#endif
- Mu = max((int)ceil(S * Mu), 2); // XXX handle 0 & 1?
- Mv = max((int)ceil(S * Mv), 2); // XXX handle 0 & 1?
+ Mu = max((int)ceilf(S * Mu), 2); // XXX handle 0 & 1?
+ Mv = max((int)ceilf(S * Mv), 2); // XXX handle 0 & 1?
/* reserve space for new verts */
int offset = params.mesh->verts.size();
diff --git a/intern/cycles/subd/subd_split.cpp b/intern/cycles/subd/subd_split.cpp
index e6603632ba7..e5b85fcfd60 100644
--- a/intern/cycles/subd/subd_split.cpp
+++ b/intern/cycles/subd/subd_split.cpp
@@ -80,9 +80,9 @@ int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend)
Plast = P;
}
- int tmin = (int)ceil(Lsum / params.dicing_rate);
- int tmax = (int)ceil((params.test_steps - 1) * Lmax /
- params.dicing_rate); // XXX paper says N instead of N-1, seems wrong?
+ int tmin = (int)ceilf(Lsum / params.dicing_rate);
+ int tmax = (int)ceilf((params.test_steps - 1) * Lmax /
+ params.dicing_rate); // XXX paper says N instead of N-1, seems wrong?
if (tmax - tmin > params.split_threshold)
return DSPLIT_NON_UNIFORM;
@@ -99,7 +99,7 @@ void DiagSplit::partition_edge(
*t1 = T(patch, *P, Pend);
}
else {
- int I = (int)floor((float)t * 0.5f);
+ int I = (int)floorf((float)t * 0.5f);
*P = interp(Pstart, Pend, (t == 0) ? 0 : I / (float)t); /* XXX is t faces or verts */
*t0 = I;
*t1 = t - I;
diff --git a/intern/cycles/test/render_graph_finalize_test.cpp b/intern/cycles/test/render_graph_finalize_test.cpp
index 7fb92bfb862..5847820bbb9 100644
--- a/intern/cycles/test/render_graph_finalize_test.cpp
+++ b/intern/cycles/test/render_graph_finalize_test.cpp
@@ -961,7 +961,7 @@ TEST_F(RenderGraph, constant_fold_blackbody)
}
/*
- * Tests: Math with all constant inputs (clamp false).
+ * Tests: Math with all constant inputs.
*/
TEST_F(RenderGraph, constant_fold_math)
{
@@ -971,29 +971,9 @@ TEST_F(RenderGraph, constant_fold_math)
builder
.add_node(ShaderNodeBuilder<MathNode>("Math")
.set(&MathNode::type, NODE_MATH_ADD)
- .set(&MathNode::use_clamp, false)
- .set("Value1", 0.7f)
- .set("Value2", 0.9f))
- .output_value("Math::Value");
-
- graph.finalize(scene);
-}
-
-/*
- * Tests: Math with all constant inputs (clamp true).
- */
-TEST_F(RenderGraph, constant_fold_math_clamp)
-{
- EXPECT_ANY_MESSAGE(log);
- CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (1).");
-
- builder
- .add_node(ShaderNodeBuilder<MathNode>("Math")
- .set(&MathNode::type, NODE_MATH_ADD)
- .set(&MathNode::use_clamp, true)
- .set("Value1", 0.7f)
- .set("Value2", 0.9f))
- .output_value("Math::Value");
+ .set("A", 0.7f)
+ .set("B", 0.9f))
+ .output_value("Math::Result");
graph.finalize(scene);
}
@@ -1003,30 +983,24 @@ TEST_F(RenderGraph, constant_fold_math_clamp)
* Includes 2 tests: constant on each side.
*/
static void build_math_partial_test_graph(ShaderGraphBuilder &builder,
- NodeMath type,
+ NodeMathType type,
float constval)
{
builder
.add_attribute("Attribute")
/* constant on the left */
- .add_node(ShaderNodeBuilder<MathNode>("Math_Cx")
- .set(&MathNode::type, type)
- .set(&MathNode::use_clamp, false)
- .set("Value1", constval))
- .add_connection("Attribute::Fac", "Math_Cx::Value2")
+ .add_node(
+ ShaderNodeBuilder<MathNode>("Math_Cx").set(&MathNode::type, type).set("A", constval))
+ .add_connection("Attribute::Fac", "Math_Cx::B")
/* constant on the right */
- .add_node(ShaderNodeBuilder<MathNode>("Math_xC")
- .set(&MathNode::type, type)
- .set(&MathNode::use_clamp, false)
- .set("Value2", constval))
- .add_connection("Attribute::Fac", "Math_xC::Value1")
+ .add_node(
+ ShaderNodeBuilder<MathNode>("Math_xC").set(&MathNode::type, type).set("B", constval))
+ .add_connection("Attribute::Fac", "Math_xC::A")
/* output sum */
- .add_node(ShaderNodeBuilder<MathNode>("Out")
- .set(&MathNode::type, NODE_MATH_ADD)
- .set(&MathNode::use_clamp, true))
- .add_connection("Math_Cx::Value", "Out::Value1")
- .add_connection("Math_xC::Value", "Out::Value2")
- .output_value("Out::Value");
+ .add_node(ShaderNodeBuilder<MathNode>("Out").set(&MathNode::type, NODE_MATH_ADD))
+ .add_connection("Math_Cx::Result", "Out::A")
+ .add_connection("Math_xC::Result", "Out::B")
+ .output_value("Out::Result");
}
/*
@@ -1168,9 +1142,9 @@ TEST_F(RenderGraph, constant_fold_vector_math)
.set("Vector1", make_float3(1.3f, 0.5f, 0.7f))
.set("Vector2", make_float3(-1.7f, 0.5f, 0.7f)))
.add_node(ShaderNodeBuilder<MathNode>("Math").set(&MathNode::type, NODE_MATH_ADD))
- .add_connection("VectorMath::Vector", "Math::Value1")
- .add_connection("VectorMath::Value", "Math::Value2")
- .output_color("Math::Value");
+ .add_connection("VectorMath::Vector", "Math::A")
+ .add_connection("VectorMath::Value", "Math::B")
+ .output_color("Math::Result");
graph.finalize(scene);
}
@@ -1180,7 +1154,7 @@ TEST_F(RenderGraph, constant_fold_vector_math)
* Includes 2 tests: constant on each side.
*/
static void build_vecmath_partial_test_graph(ShaderGraphBuilder &builder,
- NodeVectorMath type,
+ NodeVectorMathType type,
float3 constval)
{
builder
@@ -1188,18 +1162,18 @@ static void build_vecmath_partial_test_graph(ShaderGraphBuilder &builder,
/* constant on the left */
.add_node(ShaderNodeBuilder<VectorMathNode>("Math_Cx")
.set(&VectorMathNode::type, type)
- .set("Vector1", constval))
- .add_connection("Attribute::Vector", "Math_Cx::Vector2")
+ .set("A", constval))
+ .add_connection("Attribute::Vector", "Math_Cx::B")
/* constant on the right */
.add_node(ShaderNodeBuilder<VectorMathNode>("Math_xC")
.set(&VectorMathNode::type, type)
- .set("Vector2", constval))
- .add_connection("Attribute::Vector", "Math_xC::Vector1")
+ .set("B", constval))
+ .add_connection("Attribute::Vector", "Math_xC::A")
/* output sum */
.add_node(ShaderNodeBuilder<VectorMathNode>("Out").set(&VectorMathNode::type,
NODE_VECTOR_MATH_ADD))
- .add_connection("Math_Cx::Vector", "Out::Vector1")
- .add_connection("Math_xC::Vector", "Out::Vector2")
+ .add_connection("Math_Cx::Vector", "Out::A")
+ .add_connection("Math_xC::Vector", "Out::B")
.output_color("Out::Vector");
}
@@ -1537,9 +1511,9 @@ TEST_F(RenderGraph, constant_fold_convert_color_float_color)
builder.add_attribute("Attribute")
.add_node(ShaderNodeBuilder<MathNode>("MathAdd")
.set(&MathNode::type, NODE_MATH_ADD)
- .set("Value2", 0.0f))
- .add_connection("Attribute::Color", "MathAdd::Value1")
- .output_color("MathAdd::Value");
+ .set("B", 0.0f))
+ .add_connection("Attribute::Color", "MathAdd::A")
+ .output_color("MathAdd::Result");
graph.finalize(scene);
}
diff --git a/intern/cycles/util/util_color.h b/intern/cycles/util/util_color.h
index 6e61190de6b..c6937ca78fe 100644
--- a/intern/cycles/util/util_color.h
+++ b/intern/cycles/util/util_color.h
@@ -43,11 +43,29 @@ ccl_device uchar4 color_float_to_byte(float3 c)
return make_uchar4(r, g, b, 0);
}
+ccl_device uchar4 color_float4_to_uchar4(float4 c)
+{
+ uchar r, g, b, a;
+
+ r = float_to_byte(c.x);
+ g = float_to_byte(c.y);
+ b = float_to_byte(c.z);
+ a = float_to_byte(c.w);
+
+ return make_uchar4(r, g, b, a);
+}
+
ccl_device_inline float3 color_byte_to_float(uchar4 c)
{
return make_float3(c.x * (1.0f / 255.0f), c.y * (1.0f / 255.0f), c.z * (1.0f / 255.0f));
}
+ccl_device_inline float4 color_uchar4_to_float4(uchar4 c)
+{
+ return make_float4(
+ c.x * (1.0f / 255.0f), c.y * (1.0f / 255.0f), c.z * (1.0f / 255.0f), c.w * (1.0f / 255.0f));
+}
+
ccl_device float color_srgb_to_linear(float c)
{
if (c < 0.04045f)
diff --git a/intern/cycles/util/util_hash.h b/intern/cycles/util/util_hash.h
index 785482967db..20de0543597 100644
--- a/intern/cycles/util/util_hash.h
+++ b/intern/cycles/util/util_hash.h
@@ -21,39 +21,297 @@
CCL_NAMESPACE_BEGIN
-ccl_device_inline uint hash_int_2d(uint kx, uint ky)
-{
+/* ***** Jenkins Lookup3 Hash Functions ***** */
+
+/* Source: http://burtleburtle.net/bob/c/lookup3.c */
+
#define rot(x, k) (((x) << (k)) | ((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 uint hash_uint(uint kx)
+{
uint a, b, c;
+ a = b = c = 0xdeadbeef + (1 << 2) + 13;
+
+ a += kx;
+ final(a, b, c);
+ return c;
+}
+
+ccl_device_inline uint hash_uint2(uint kx, uint ky)
+{
+ uint a, b, c;
a = b = c = 0xdeadbeef + (2 << 2) + 13;
+
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline uint hash_uint3(uint kx, uint ky, uint kz)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeef + (3 << 2) + 13;
+
+ c += kz;
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+ccl_device_inline uint hash_uint4(uint kx, uint ky, uint kz, uint kw)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeef + (4 << 2) + 13;
+
a += kx;
b += ky;
+ c += kz;
+ mix(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);
+ a += kw;
+ final(a, b, c);
return c;
+}
#undef rot
+#undef final
+#undef mix
+
+#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 uint hash_int(uint k)
+ccl_device_inline ssei hash_ssei4(ssei kx, ssei ky, ssei kz, ssei kw)
{
- return hash_int_2d(k, 0);
+ 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
+
+/* Hashing uint or uint[234] into a float in the range [0, 1]. */
+
+ccl_device_inline float hash_uint_to_float(uint kx)
+{
+ return (float)hash_uint(kx) / (float)0xFFFFFFFFu;
+}
+
+ccl_device_inline float hash_uint2_to_float(uint kx, uint ky)
+{
+ return (float)hash_uint2(kx, ky) / (float)0xFFFFFFFFu;
+}
+
+ccl_device_inline float hash_uint3_to_float(uint kx, uint ky, uint kz)
+{
+ return (float)hash_uint3(kx, ky, kz) / (float)0xFFFFFFFFu;
+}
+
+ccl_device_inline float hash_uint4_to_float(uint kx, uint ky, uint kz, uint kw)
+{
+ return (float)hash_uint4(kx, ky, kz, kw) / (float)0xFFFFFFFFu;
+}
+
+/* Hashing float or float[234] into a float in the range [0, 1]. */
+
+ccl_device_inline float hash_float_to_float(float k)
+{
+ return hash_uint_to_float(__float_as_uint(k));
+}
+
+ccl_device_inline float hash_float2_to_float(float2 k)
+{
+ return hash_uint2_to_float(__float_as_uint(k.x), __float_as_uint(k.y));
+}
+
+ccl_device_inline float hash_float3_to_float(float3 k)
+{
+ return hash_uint3_to_float(__float_as_uint(k.x), __float_as_uint(k.y), __float_as_uint(k.z));
+}
+
+ccl_device_inline float hash_float4_to_float(float4 k)
+{
+ return hash_uint4_to_float(
+ __float_as_uint(k.x), __float_as_uint(k.y), __float_as_uint(k.z), __float_as_uint(k.w));
+}
+
+/* Hashing float[234] into float[234] of components in the range [0, 1]. */
+
+ccl_device_inline float2 hash_float2_to_float2(float2 k)
+{
+ return make_float2(hash_float2_to_float(k), hash_float3_to_float(make_float3(k.x, k.y, 1.0)));
+}
+
+ccl_device_inline float3 hash_float3_to_float3(float3 k)
+{
+ return make_float3(hash_float3_to_float(k),
+ hash_float4_to_float(make_float4(k.x, k.y, k.z, 1.0)),
+ hash_float4_to_float(make_float4(k.x, k.y, k.z, 2.0)));
+}
+
+ccl_device_inline float4 hash_float4_to_float4(float4 k)
+{
+ return make_float4(hash_float4_to_float(k),
+ hash_float4_to_float(make_float4(k.w, k.x, k.y, k.z)),
+ hash_float4_to_float(make_float4(k.z, k.w, k.x, k.y)),
+ hash_float4_to_float(make_float4(k.y, k.z, k.w, k.x)));
+}
+
+/* Hashing float or float[234] into float3 of components in range [0, 1]. */
+
+ccl_device_inline float3 hash_float_to_float3(float k)
+{
+ return make_float3(hash_float_to_float(k),
+ hash_float2_to_float(make_float2(k, 1.0)),
+ hash_float2_to_float(make_float2(k, 2.0)));
+}
+
+ccl_device_inline float3 hash_float2_to_float3(float2 k)
+{
+ return make_float3(hash_float2_to_float(k),
+ hash_float3_to_float(make_float3(k.x, k.y, 1.0)),
+ hash_float3_to_float(make_float3(k.x, k.y, 2.0)));
+}
+
+ccl_device_inline float3 hash_float4_to_float3(float4 k)
+{
+ return make_float3(hash_float4_to_float(k),
+ hash_float4_to_float(make_float4(k.z, k.x, k.w, k.y)),
+ hash_float4_to_float(make_float4(k.w, k.z, k.y, k.x)));
}
#ifndef __KERNEL_GPU__
@@ -68,11 +326,6 @@ static inline uint hash_string(const char *str)
}
#endif
-ccl_device_inline float hash_int_01(uint k)
-{
- return (float)hash_int(k) * (1.0f / (float)0xFFFFFFFF);
-}
-
CCL_NAMESPACE_END
#endif /* __UTIL_HASH_H__ */
diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h
index dde0d31f467..7b0a967f8bb 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_math_float2.h b/intern/cycles/util/util_math_float2.h
index 9feaf042d19..4078e3be68f 100644
--- a/intern/cycles/util/util_math_float2.h
+++ b/intern/cycles/util/util_math_float2.h
@@ -46,6 +46,7 @@ ccl_device_inline float2 operator/=(float2 &a, float f);
ccl_device_inline bool operator==(const float2 &a, const float2 &b);
ccl_device_inline bool operator!=(const float2 &a, const float2 &b);
+ccl_device_inline float distance(const float2 &a, const float2 &b);
ccl_device_inline bool is_zero(const float2 &a);
ccl_device_inline float average(const float2 &a);
ccl_device_inline float dot(const float2 &a, const float2 &b);
@@ -60,8 +61,11 @@ ccl_device_inline float2 clamp(const float2 &a, const float2 &mn, const float2 &
ccl_device_inline float2 fabs(const float2 &a);
ccl_device_inline float2 as_float2(const float4 &a);
ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t);
+ccl_device_inline float2 floor(const float2 &a);
#endif /* !__KERNEL_OPENCL__ */
+ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b);
+
/*******************************************************************************
* Definition.
*/
@@ -149,6 +153,11 @@ ccl_device_inline bool operator!=(const float2 &a, const float2 &b)
return !(a == b);
}
+ccl_device_inline float distance(const float2 &a, const float2 &b)
+{
+ return len(a - b);
+}
+
ccl_device_inline bool is_zero(const float2 &a)
{
return (a.x == 0.0f && a.y == 0.0f);
@@ -226,8 +235,19 @@ ccl_device_inline float2 mix(const float2 &a, const float2 &b, float t)
return a + t * (b - a);
}
+ccl_device_inline float2 floor(const float2 &a)
+{
+
+ return make_float2(floorf(a.x), floorf(a.y));
+}
+
#endif /* !__KERNEL_OPENCL__ */
+ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b)
+{
+ return make_float2((b != 0.0f) ? a.x / b : 0.0f, (b != 0.0f) ? a.y / b : 0.0f);
+}
+
CCL_NAMESPACE_END
#endif /* __UTIL_MATH_FLOAT2_H__ */
diff --git a/intern/cycles/util/util_math_float3.h b/intern/cycles/util/util_math_float3.h
index 554b7408148..ec59f2b2d7b 100644
--- a/intern/cycles/util/util_math_float3.h
+++ b/intern/cycles/util/util_math_float3.h
@@ -47,6 +47,7 @@ ccl_device_inline float3 operator/=(float3 &a, float f);
ccl_device_inline bool operator==(const float3 &a, const float3 &b);
ccl_device_inline bool operator!=(const float3 &a, const float3 &b);
+ccl_device_inline float distance(const float3 &a, const float3 &b);
ccl_device_inline float dot(const float3 &a, const float3 &b);
ccl_device_inline float dot_xy(const float3 &a, const float3 &b);
ccl_device_inline float3 cross(const float3 &a, const float3 &b);
@@ -58,6 +59,9 @@ ccl_device_inline float3 fabs(const float3 &a);
ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t);
ccl_device_inline float3 rcp(const float3 &a);
ccl_device_inline float3 sqrt(const float3 &a);
+ccl_device_inline float3 floor(const float3 &a);
+ccl_device_inline float3 ceil(const float3 &a);
+ccl_device_inline float3 fract(const float3 &a);
#endif /* !__KERNEL_OPENCL__ */
ccl_device_inline float min3(float3 a);
@@ -65,10 +69,15 @@ ccl_device_inline float max3(float3 a);
ccl_device_inline float len(const float3 a);
ccl_device_inline float len_squared(const float3 a);
+ccl_device_inline float3 reflect(const float3 i, const float3 n);
+ccl_device_inline float3 project(const float3 v, const float3 v_proj);
+
ccl_device_inline float3 saturate3(float3 a);
ccl_device_inline float3 safe_normalize(const float3 a);
ccl_device_inline float3 normalize_len(const float3 a, float *t);
ccl_device_inline float3 safe_normalize_len(const float3 a, float *t);
+ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b);
+ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b);
ccl_device_inline float3 interp(float3 a, float3 b, float t);
ccl_device_inline float3 sqr3(float3 a);
@@ -205,6 +214,11 @@ ccl_device_inline bool operator!=(const float3 &a, const float3 &b)
return !(a == b);
}
+ccl_device_inline float distance(const float3 &a, const float3 &b)
+{
+ return len(a - b);
+}
+
ccl_device_inline float dot(const float3 &a, const float3 &b)
{
# if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
@@ -281,6 +295,29 @@ ccl_device_inline float3 sqrt(const float3 &a)
# endif
}
+ccl_device_inline float3 floor(const float3 &a)
+{
+# ifdef __KERNEL_SSE__
+ return float3(_mm_floor_ps(a));
+# else
+ return make_float3(floorf(a.x), floorf(a.y), floorf(a.z));
+# endif
+}
+
+ccl_device_inline float3 ceil(const float3 &a)
+{
+# ifdef __KERNEL_SSE__
+ return float3(_mm_ceil_ps(a));
+# else
+ return make_float3(ceilf(a.x), ceilf(a.y), ceilf(a.z));
+# endif
+}
+
+ccl_device_inline float3 fract(const float3 &a)
+{
+ return a - floor(a);
+}
+
ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t)
{
return a + t * (b - a);
@@ -321,6 +358,19 @@ ccl_device_inline float len_squared(const float3 a)
return dot(a, a);
}
+ccl_device_inline float3 reflect(const float3 i, const float3 n)
+{
+ float3 normal = normalize(n);
+ return i - 2 * normal * dot(i, normal);
+}
+
+ccl_device_inline float3 project(const float3 v, const float3 v_proj)
+{
+ float lenSquared = dot(v_proj, v_proj);
+ return (lenSquared != 0.0f) ? (dot(v, v_proj) / lenSquared) * v_proj :
+ make_float3(0.0f, 0.0f, 0.0f);
+}
+
ccl_device_inline float3 saturate3(float3 a)
{
return make_float3(saturate(a.x), saturate(a.y), saturate(a.z));
@@ -345,6 +395,19 @@ ccl_device_inline float3 safe_normalize_len(const float3 a, float *t)
return (*t != 0.0f) ? a / (*t) : a;
}
+ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b)
+{
+ return make_float3((b.x != 0.0f) ? a.x / b.x : 0.0f,
+ (b.y != 0.0f) ? a.y / b.y : 0.0f,
+ (b.z != 0.0f) ? a.z / b.z : 0.0f);
+}
+
+ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b)
+{
+ return make_float3(
+ (b != 0.0f) ? a.x / b : 0.0f, (b != 0.0f) ? a.y / b : 0.0f, (b != 0.0f) ? a.z / b : 0.0f);
+}
+
ccl_device_inline float3 interp(float3 a, float3 b, float t)
{
return a + t * (b - a);
diff --git a/intern/cycles/util/util_math_float4.h b/intern/cycles/util/util_math_float4.h
index 1fb886572e3..0624dadf5ad 100644
--- a/intern/cycles/util/util_math_float4.h
+++ b/intern/cycles/util/util_math_float4.h
@@ -46,6 +46,7 @@ ccl_device_inline int4 operator>=(const float4 &a, const float4 &b);
ccl_device_inline int4 operator<=(const float4 &a, const float4 &b);
ccl_device_inline bool operator==(const float4 &a, const float4 &b);
+ccl_device_inline float distance(const float4 &a, const float4 &b);
ccl_device_inline float dot(const float4 &a, const float4 &b);
ccl_device_inline float len_squared(const float4 &a);
ccl_device_inline float4 rcp(const float4 &a);
@@ -53,16 +54,20 @@ ccl_device_inline float4 sqrt(const float4 &a);
ccl_device_inline float4 sqr(const float4 &a);
ccl_device_inline float4 cross(const float4 &a, const float4 &b);
ccl_device_inline bool is_zero(const float4 &a);
-ccl_device_inline float average(const float4 &a);
ccl_device_inline float len(const float4 &a);
ccl_device_inline float4 normalize(const float4 &a);
ccl_device_inline float4 safe_normalize(const float4 &a);
ccl_device_inline float4 min(const float4 &a, const float4 &b);
ccl_device_inline float4 max(const float4 &a, const float4 &b);
+ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t);
ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 &mx);
ccl_device_inline float4 fabs(const float4 &a);
+ccl_device_inline float4 floor(const float4 &a);
#endif /* !__KERNEL_OPENCL__*/
+ccl_device_inline float average_float4(const float4 a);
+ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b);
+
#ifdef __KERNEL_SSE__
template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
__forceinline const float4 shuffle(const float4 &b);
@@ -213,6 +218,11 @@ ccl_device_inline bool operator==(const float4 &a, const float4 &b)
# endif
}
+ccl_device_inline float distance(const float4 &a, const float4 &b)
+{
+ return len(a - b);
+}
+
ccl_device_inline float dot(const float4 &a, const float4 &b)
{
# if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
@@ -286,11 +296,6 @@ ccl_device_inline float4 reduce_add(const float4 &a)
# endif
}
-ccl_device_inline float average(const float4 &a)
-{
- return reduce_add(a).x * 0.25f;
-}
-
ccl_device_inline float len(const float4 &a)
{
return sqrtf(dot(a, a));
@@ -325,6 +330,11 @@ ccl_device_inline float4 max(const float4 &a, const float4 &b)
# endif
}
+ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t)
+{
+ return a + t * (b - a);
+}
+
ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 &mx)
{
return min(max(a, mn), mx);
@@ -338,8 +348,31 @@ ccl_device_inline float4 fabs(const float4 &a)
return make_float4(fabsf(a.x), fabsf(a.y), fabsf(a.z), fabsf(a.w));
# endif
}
+
+ccl_device_inline float4 floor(const float4 &a)
+{
+# ifdef __KERNEL_SSE__
+ return float4(_mm_floor_ps(a));
+# else
+ return make_float4(floorf(a.x), floorf(a.y), floorf(a.z), floorf(a.w));
+# endif
+}
+
#endif /* !__KERNEL_OPENCL__*/
+ccl_device_inline float average_float4(const float4 a)
+{
+ return (a.x + a.y + a.z + a.w) * 0.25f;
+}
+
+ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b)
+{
+ return make_float4((b != 0.0f) ? a.x / b : 0.0f,
+ (b != 0.0f) ? a.y / b : 0.0f,
+ (b != 0.0f) ? a.z / b : 0.0f,
+ (b != 0.0f) ? a.w / b : 0.0f);
+}
+
#ifdef __KERNEL_SSE__
template<size_t index_0, size_t index_1, size_t index_2, size_t index_3>
__forceinline const float4 shuffle(const float4 &b)
diff --git a/intern/cycles/util/util_param.h b/intern/cycles/util/util_param.h
index cfbe416aba1..3f8e2d6d700 100644
--- a/intern/cycles/util/util_param.h
+++ b/intern/cycles/util/util_param.h
@@ -29,6 +29,11 @@ CCL_NAMESPACE_BEGIN
OIIO_NAMESPACE_USING
static constexpr TypeDesc TypeFloat2(TypeDesc::FLOAT, TypeDesc::VEC2);
+static constexpr TypeDesc TypeRGBA(TypeDesc::FLOAT, TypeDesc::VEC4, TypeDesc::COLOR);
+static constexpr TypeDesc TypeFloatArray4(TypeDesc::FLOAT,
+ TypeDesc::SCALAR,
+ TypeDesc::NOSEMANTICS,
+ 4);
CCL_NAMESPACE_END
diff --git a/intern/cycles/util/util_ssef.h b/intern/cycles/util/util_ssef.h
index e6610dbb197..b28d427685b 100644
--- a/intern/cycles/util/util_ssef.h
+++ b/intern/cycles/util/util_ssef.h
@@ -533,6 +533,15 @@ __forceinline ssei floori(const ssef &a)
}
////////////////////////////////////////////////////////////////////////////////
+/// Common Functions
+////////////////////////////////////////////////////////////////////////////////
+
+__forceinline ssef mix(const ssef &a, const ssef &b, const ssef &t)
+{
+ return madd(t, b, (ssef(1.0f) - t) * a);
+}
+
+////////////////////////////////////////////////////////////////////////////////
/// Movement/Shifting/Shuffling Functions
////////////////////////////////////////////////////////////////////////////////
@@ -561,6 +570,21 @@ template<> __forceinline const ssef shuffle<2, 3, 2, 3>(const ssef &a)
return _mm_movehl_ps(a, a);
}
+template<size_t i0, size_t i1> __forceinline const ssef shuffle(const ssef &b)
+{
+ return _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(b), _MM_SHUFFLE(i1, i0, i1, i0)));
+}
+
+template<> __forceinline const ssef shuffle<0, 1>(const ssef &a)
+{
+ return _mm_movelh_ps(a, a);
+}
+
+template<> __forceinline const ssef shuffle<2, 3>(const ssef &a)
+{
+ return _mm_movehl_ps(a, a);
+}
+
template<size_t i0, size_t i1, size_t i2, size_t i3>
__forceinline const ssef shuffle(const ssef &a, const ssef &b)
{
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..5f15cf95a64 100644
--- a/intern/cycles/util/util_transform.h
+++ b/intern/cycles/util/util_transform.h
@@ -148,6 +148,35 @@ ccl_device_inline Transform make_transform(float a,
return t;
}
+ccl_device_inline Transform euler_to_transform(const float3 euler)
+{
+ Transform t;
+ float c1, c2, c3, s1, s2, s3;
+
+ c1 = cosf(euler.x);
+ c2 = cosf(euler.y);
+ c3 = cosf(euler.z);
+ s1 = sinf(euler.x);
+ s2 = sinf(euler.y);
+ s3 = sinf(euler.z);
+
+ t.x.x = c2 * c3;
+ t.y.x = c1 * s3 + c3 * s1 * s2;
+ t.z.x = s1 * s3 - c1 * c3 * s2;
+
+ t.x.y = -c2 * s3;
+ t.y.y = c1 * c3 - s1 * s2 * s3;
+ t.z.y = c3 * s1 + c1 * s2 * s3;
+
+ t.x.z = s2;
+ t.y.z = -c2 * s1;
+ t.z.z = c1 * c2;
+
+ 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/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 01ae9c48fd2..2497a9857a9 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -189,6 +189,8 @@ shader_node_categories = [
NodeItem("ShaderNodeParticleInfo"),
NodeItem("ShaderNodeCameraData"),
NodeItem("ShaderNodeUVMap"),
+ NodeItem("ShaderNodeVertexColor"),
+ NodeItem("ShaderNodeVolumeInfo"),
NodeItem("ShaderNodeUVAlongStroke", poll=line_style_shader_nodes_poll),
NodeItem("NodeGroupInput", poll=group_input_output_item_poll),
]),
@@ -237,6 +239,7 @@ shader_node_categories = [
NodeItem("ShaderNodeTexBrick"),
NodeItem("ShaderNodeTexPointDensity"),
NodeItem("ShaderNodeTexIES"),
+ NodeItem("ShaderNodeTexWhiteNoise"),
]),
ShaderNodeCategory("SH_NEW_OP_COLOR", "Color", items=[
NodeItem("ShaderNodeMixRGB"),
@@ -258,6 +261,8 @@ shader_node_categories = [
NodeItem("ShaderNodeVectorTransform"),
]),
ShaderNodeCategory("SH_NEW_CONVERTOR", "Converter", items=[
+ NodeItem("ShaderNodeMapRange"),
+ NodeItem("ShaderNodeClamp"),
NodeItem("ShaderNodeMath"),
NodeItem("ShaderNodeValToRGB"),
NodeItem("ShaderNodeRGBToBW"),
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 8a107aac538..ee877694b60 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -616,6 +616,7 @@ void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node);
int nodeSocketIsHidden(struct bNodeSocket *sock);
void ntreeTagUsedSockets(struct bNodeTree *ntree);
+void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available);
/* Node Clipboard */
void BKE_node_clipboard_init(struct bNodeTree *ntree);
@@ -895,7 +896,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_CURVE_RGB 111
#define SH_NODE_CAMERA 114
#define SH_NODE_MATH 115
-#define SH_NODE_VECT_MATH 116
+#define SH_NODE_VECTOR_MATH 116
#define SH_NODE_SQUEEZE 117
//#define SH_NODE_MATERIAL_EXT 118
#define SH_NODE_INVERT 119
@@ -976,6 +977,11 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
#define SH_NODE_VOLUME_PRINCIPLED 200
/* 201..700 occupied by other node types, continue from 701 */
#define SH_NODE_BSDF_HAIR_PRINCIPLED 701
+#define SH_NODE_MAP_RANGE 702
+#define SH_NODE_CLAMP 703
+#define SH_NODE_TEX_WHITE_NOISE 704
+#define SH_NODE_VOLUME_INFO 705
+#define SH_NODE_VERTEX_COLOR 706
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 775f6eb37a7..ce54015da8f 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -2799,6 +2799,16 @@ int nodeSocketIsHidden(bNodeSocket *sock)
return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0);
}
+void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available)
+{
+ if (is_available) {
+ sock->flag &= ~SOCK_UNAVAIL;
+ }
+ else {
+ sock->flag |= SOCK_UNAVAIL;
+ }
+}
+
/* ************** Node Clipboard *********** */
#define USE_NODE_CB_VALIDATE
@@ -3222,11 +3232,6 @@ void ntreeTagUsedSockets(bNodeTree *ntree)
}
for (link = ntree->links.first; link; link = link->next) {
- /* link is unused if either side is disabled */
- if ((link->fromsock->flag & SOCK_UNAVAIL) || (link->tosock->flag & SOCK_UNAVAIL)) {
- continue;
- }
-
link->fromsock->flag |= SOCK_IN_USE;
link->tosock->flag |= SOCK_IN_USE;
}
@@ -3856,6 +3861,8 @@ static void registerShaderNodes(void)
register_node_type_sh_mapping();
register_node_type_sh_curve_vec();
register_node_type_sh_curve_rgb();
+ register_node_type_sh_map_range();
+ register_node_type_sh_clamp();
register_node_type_sh_math();
register_node_type_sh_vect_math();
register_node_type_sh_vect_transform();
@@ -3882,6 +3889,8 @@ static void registerShaderNodes(void)
register_node_type_sh_tex_coord();
register_node_type_sh_particle_info();
register_node_type_sh_bump();
+ register_node_type_sh_volume_info();
+ register_node_type_sh_vertex_color();
register_node_type_sh_background();
register_node_type_sh_bsdf_anisotropic();
@@ -3925,6 +3934,7 @@ static void registerShaderNodes(void)
register_node_type_sh_tex_brick();
register_node_type_sh_tex_pointdensity();
register_node_type_sh_tex_ies();
+ register_node_type_sh_tex_white_noise();
}
static void registerTextureNodes(void)
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 2815046865d..8acc3d5f186 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -139,6 +139,8 @@ MINLINE void mul_v2_v2_cw(float r[2], const float mat[2], const float vec[2]);
MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]);
MINLINE float mul_project_m4_v3_zfac(const float mat[4][4],
const float co[3]) ATTR_WARN_UNUSED_RESULT;
+MINLINE void div_v3_v3v3(float r[3], const float a[3], const float b[3]);
+MINLINE void div_v3_v3v3_safe(float r[3], const float a[3], const float b[3]);
MINLINE float dot_m3_v3_row_x(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m3_v3_row_y(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
MINLINE float dot_m3_v3_row_z(const float M[3][3], const float a[3]) ATTR_WARN_UNUSED_RESULT;
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 865c2f5dc25..d05de6bb267 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -684,6 +684,20 @@ MINLINE void mul_v3_v3v3(float r[3], const float v1[3], const float v2[3])
r[2] = v1[2] * v2[2];
}
+MINLINE void div_v3_v3v3(float r[3], const float v1[3], const float v2[3])
+{
+ r[0] = v1[0] / v2[0];
+ r[1] = v1[1] / v2[1];
+ r[2] = v1[2] / v2[2];
+}
+
+MINLINE void div_v3_v3v3_safe(float r[3], const float v1[3], const float v2[3])
+{
+ r[0] = (v2[0] != 0.0f) ? v1[0] / v2[0] : 0.0f;
+ r[1] = (v2[1] != 0.0f) ? v1[1] / v2[1] : 0.0f;
+ r[2] = (v2[2] != 0.0f) ? v1[2] / v2[2] : 0.0f;
+}
+
MINLINE void mul_v2_v2v2(float r[2], const float a[2], const float b[2])
{
r[0] = a[0] * b[0];
diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c
index cebe15e2719..a6803e6164b 100644
--- a/source/blender/blenloader/intern/versioning_cycles.c
+++ b/source/blender/blenloader/intern/versioning_cycles.c
@@ -39,11 +39,18 @@
#include "BKE_main.h"
#include "BKE_node.h"
+#include "MEM_guardedalloc.h"
+
#include "IMB_colormanagement.h"
#include "BLO_readfile.h"
#include "readfile.h"
+static bool socket_is_used(bNodeSocket *sock)
+{
+ return sock->flag & SOCK_IN_USE;
+}
+
static float *cycles_node_socket_float_value(bNodeSocket *socket)
{
bNodeSocketValueFloat *socket_data = socket->default_value;
@@ -56,6 +63,12 @@ static float *cycles_node_socket_rgba_value(bNodeSocket *socket)
return socket_data->value;
}
+static float *cycles_node_socket_vector_value(bNodeSocket *socket)
+{
+ bNodeSocketValueVector *socket_data = socket->default_value;
+ return socket_data->value;
+}
+
static IDProperty *cycles_properties_from_ID(ID *id)
{
IDProperty *idprop = IDP_GetProperties(id, false);
@@ -185,7 +198,7 @@ static void square_roughness_node_insert(bNodeTree *ntree)
/* Add sqrt node. */
bNode *node = nodeAddStaticNode(NULL, ntree, SH_NODE_MATH);
- node->custom1 = NODE_MATH_POW;
+ node->custom1 = NODE_MATH_POWER;
node->locx = 0.5f * (fromnode->locx + tonode->locx);
node->locy = 0.5f * (fromnode->locy + tonode->locy);
@@ -385,6 +398,555 @@ static void light_emission_unify(Light *light, const char *engine)
}
}
+/* The names of the sockets of the Math node were changed. So we have to update
+ * them here. The sockets' identifiers needs to be updated as well since they
+ * are autmatically generated from the names.
+ */
+static void update_math_socket_names_and_identifiers(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_MATH) {
+ bNodeSocket *sockA = node->inputs.first;
+ bNodeSocket *sockB = sockA->next;
+ bNodeSocket *sockResult = node->outputs.first;
+
+ strcpy(sockA->name, "A");
+ strcpy(sockB->name, "B");
+ strcpy(sockResult->name, "Result");
+
+ strcpy(sockA->identifier, "A");
+ strcpy(sockB->identifier, "B");
+ strcpy(sockResult->identifier, "Result");
+ }
+ }
+}
+
+/* The B input of the Math node is no longer used for single-operand operators.
+ * Previously, if the B input was linked and the A input was not, the B input
+ * was used as the input of the operator. To correct this, we move the link
+ * from B to A if B is linked and A is not.
+ */
+static void update_math_single_operand_operators(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_MATH) {
+ if (ELEM(node->custom1,
+ NODE_MATH_SQRT,
+ NODE_MATH_CEIL,
+ NODE_MATH_SINE,
+ NODE_MATH_ROUND,
+ NODE_MATH_FLOOR,
+ NODE_MATH_COSINE,
+ NODE_MATH_ARCSINE,
+ NODE_MATH_TANGENT,
+ NODE_MATH_ABSOLUTE,
+ NODE_MATH_FRACTION,
+ NODE_MATH_ARCCOSINE,
+ NODE_MATH_ARCTANGENT)) {
+ bNodeSocket *sockA = nodeFindSocket(node, SOCK_IN, "A");
+ bNodeSocket *sockB = nodeFindSocket(node, SOCK_IN, "B");
+ if (!sockA->link && sockB->link) {
+ nodeAddLink(ntree, sockB->link->fromnode, sockB->link->fromsock, node, sockA);
+ nodeRemLink(ntree, sockB->link);
+ need_update = true;
+ }
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* The clamp option of the Math node was removed. To correct this, we add a
+ * Clamp node if the clamp option was enabled.
+ */
+static void update_math_clamp_option(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_MATH && node->custom2) {
+ bNode *clampNode = nodeAddStaticNode(NULL, ntree, SH_NODE_CLAMP);
+ clampNode->locx = node->locx + node->width + 20.0f;
+ clampNode->locy = node->locy;
+
+ bNodeSocket *sockMathResult = nodeFindSocket(node, SOCK_OUT, "Result");
+ bNodeSocket *sockClampValue = nodeFindSocket(clampNode, SOCK_IN, "Value");
+ bNodeSocket *sockClampResult = nodeFindSocket(clampNode, SOCK_OUT, "Result");
+
+ /* Iterate backwards from end so we don't encounter newly added links. */
+ for (bNodeLink *link = ntree->links.last; link; link = link->prev) {
+ if (link->fromsock == sockMathResult) {
+ nodeAddLink(ntree, clampNode, sockClampResult, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+ nodeAddLink(ntree, node, sockMathResult, clampNode, sockClampValue);
+ need_update = true;
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* The names of the sockets of the Vector Math node were changed. So we have to
+ * update them here. The sockets' identifiers needs to be updated as well since
+ * they are autmatically generated from the names.
+ */
+static void update_vector_math_socket_names_and_identifiers(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_VECTOR_MATH) {
+ bNodeSocket *sockA = node->inputs.first;
+ bNodeSocket *sockB = sockA->next;
+
+ strcpy(sockA->name, "A");
+ strcpy(sockB->name, "B");
+
+ strcpy(sockA->identifier, "A");
+ strcpy(sockB->identifier, "B");
+ }
+ }
+}
+
+/* The Value output of the Vector Math node is no longer available in the Add
+ * and Subtract operators. Previously, this Value output was computed from the
+ * Vector output V as follows:
+ *
+ * Value = (abs(V.x) + abs(V.y) + abs(V.z)) / 3
+ *
+ * Or more compactly using vector operators:
+ *
+ * Value = dot(abs(V), (1 / 3, 1 / 3, 1 / 3))
+ *
+ * To correct this, if the Value output was used, we are going to compute
+ * it using the second equation by adding an absolute and a dot node, then
+ * connect them appropriately.
+ */
+static void update_vector_math_add_and_subtract_operators(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_VECTOR_MATH) {
+ bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
+ if (socket_is_used(sockOutValue) &&
+ ELEM(node->custom1, NODE_VECTOR_MATH_ADD, NODE_VECTOR_MATH_SUBTRACT)) {
+
+ bNode *absNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ absNode->custom1 = NODE_VECTOR_MATH_ABSOLUTE;
+ absNode->locx = node->locx + node->width + 20.0f;
+ absNode->locy = node->locy;
+
+ bNode *dotNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ dotNode->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
+ dotNode->locx = absNode->locx + absNode->width + 20.0f;
+ dotNode->locy = absNode->locy;
+ bNodeSocket *sockDotB = nodeFindSocket(dotNode, SOCK_IN, "B");
+ bNodeSocket *sockDotOutValue = nodeFindSocket(dotNode, SOCK_OUT, "Value");
+ copy_v3_fl(cycles_node_socket_vector_value(sockDotB), 1 / 3.0f);
+
+ /* Iterate backwards from end so we don't encounter newly added links. */
+ for (bNodeLink *link = ntree->links.last; link; link = link->prev) {
+ if (link->fromsock == sockOutValue) {
+ nodeAddLink(ntree, dotNode, sockDotOutValue, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+
+ bNodeSocket *sockAbsA = nodeFindSocket(absNode, SOCK_IN, "A");
+ bNodeSocket *sockDotA = nodeFindSocket(dotNode, SOCK_IN, "A");
+ bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
+ bNodeSocket *sockAbsOutVector = nodeFindSocket(absNode, SOCK_OUT, "Vector");
+
+ nodeAddLink(ntree, node, sockOutVector, absNode, sockAbsA);
+ nodeAddLink(ntree, absNode, sockAbsOutVector, dotNode, sockDotA);
+
+ need_update = true;
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* The Vector output of the Vector Math node is no longer available in the Dot
+ * Product operator. Previously, this Vector was always zero initialized. To
+ * correct this, we zero out any socket the Vector Output was connected to.
+ */
+static void update_vector_math_dot_product_operator(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_VECTOR_MATH) {
+ bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
+ if (socket_is_used(sockOutVector) && node->custom1 == NODE_VECTOR_MATH_DOT_PRODUCT) {
+ for (bNodeLink *link = ntree->links.first; link; link = link->next) {
+ if (link->fromsock == sockOutVector) {
+ switch (link->tosock->type) {
+ case SOCK_FLOAT:
+ *cycles_node_socket_float_value(link->tosock) = 0.0f;
+ break;
+ case SOCK_VECTOR:
+ copy_v3_fl(cycles_node_socket_vector_value(link->tosock), 0.0f);
+ break;
+ case SOCK_RGBA:
+ copy_v4_fl(cycles_node_socket_rgba_value(link->tosock), 0.0f);
+ break;
+ }
+ nodeRemLink(ntree, link);
+ }
+ }
+ need_update = true;
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* Previously, the Vector output of the cross product operator was normalized.
+ * To correct this, a Normalize node is added to normalize the output if used.
+ * Moreover, the Value output was removed. This Value was equal to the length
+ * of the cross product. To correct this, a Length node is added if needed.
+ */
+static void update_vector_math_cross_product_operator(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_VECTOR_MATH) {
+ if (node->custom1 == NODE_VECTOR_MATH_CROSS_PRODUCT) {
+ bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
+ if (socket_is_used(sockOutVector)) {
+ bNode *normalizeNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ normalizeNode->custom1 = NODE_VECTOR_MATH_NORMALIZE;
+ normalizeNode->locx = node->locx + node->width + 20.0f;
+ normalizeNode->locy = node->locy;
+ bNodeSocket *sockNormalizeOut = nodeFindSocket(normalizeNode, SOCK_OUT, "Vector");
+
+ /* Iterate backwards from end so we don't encounter newly added links. */
+ for (bNodeLink *link = ntree->links.last; link; link = link->prev) {
+ if (link->fromsock == sockOutVector) {
+ nodeAddLink(ntree, normalizeNode, sockNormalizeOut, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+ bNodeSocket *sockNormalizeA = nodeFindSocket(normalizeNode, SOCK_IN, "A");
+ nodeAddLink(ntree, node, sockOutVector, normalizeNode, sockNormalizeA);
+
+ need_update = true;
+ }
+
+ bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
+ if (socket_is_used(sockOutValue)) {
+ bNode *lengthNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ lengthNode->custom1 = NODE_VECTOR_MATH_LENGTH;
+ lengthNode->locx = node->locx + node->width + 20.0f;
+ if (socket_is_used(sockOutVector)) {
+ lengthNode->locy = node->locy - lengthNode->height - 20.0f;
+ }
+ else {
+ lengthNode->locy = node->locy;
+ }
+ bNodeSocket *sockLengthOut = nodeFindSocket(lengthNode, SOCK_OUT, "Value");
+
+ /* Iterate backwards from end so we don't encounter newly added links. */
+ for (bNodeLink *link = ntree->links.last; link; link = link->prev) {
+ if (link->fromsock == sockOutValue) {
+ nodeAddLink(ntree, lengthNode, sockLengthOut, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+ bNodeSocket *sockLengthA = nodeFindSocket(lengthNode, SOCK_IN, "A");
+ nodeAddLink(ntree, node, sockOutVector, lengthNode, sockLengthA);
+
+ need_update = true;
+ }
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* The Value output of the Vector Math node is no longer available in the
+ * Normalize operator. This Value output was equal to the length of the
+ * the input vector A. To correct this, we either add a Length node or
+ * convert the Normalize node into a Length node, depending on if the
+ * Vector output is needed.
+ */
+static void update_vector_math_normalize_operator(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_VECTOR_MATH) {
+ bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
+ if (node->custom1 == NODE_VECTOR_MATH_NORMALIZE && socket_is_used(sockOutValue)) {
+ bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
+ if (socket_is_used(sockOutVector)) {
+ bNode *lengthNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ lengthNode->custom1 = NODE_VECTOR_MATH_LENGTH;
+ lengthNode->locx = node->locx + node->width + 20.0f;
+ lengthNode->locy = node->locy;
+ bNodeSocket *sockLengthValue = nodeFindSocket(lengthNode, SOCK_OUT, "Value");
+
+ /* Iterate backwards from end so we don't encounter newly added links. */
+ for (bNodeLink *link = ntree->links.last; link; link = link->prev) {
+ if (link->fromsock == sockOutValue) {
+ nodeAddLink(ntree, lengthNode, sockLengthValue, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+ bNodeLink *link = nodeFindSocket(node, SOCK_IN, "A")->link;
+ bNodeSocket *sockLengthA = nodeFindSocket(lengthNode, SOCK_IN, "A");
+ nodeAddLink(ntree, link->fromnode, link->fromsock, lengthNode, sockLengthA);
+
+ need_update = true;
+ }
+ else {
+ node->custom1 = NODE_VECTOR_MATH_LENGTH;
+ }
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* The Average operator is no longer available in the Vector Math node.
+ * This altered the order of operators in the vector math type enum.
+ * To fix this, we remap the enum values according to the following rules:
+ *
+ * NODE_VECTOR_MATH_DOT_PRODUCT : 3 -> 7
+ * NODE_VECTOR_MATH_NORMALIZE : 5 -> 11
+ *
+ * Additionally, NODE_VECTOR_MATH_AVERAGE is assigned a value of -1 to be
+ * identified later in the versioning code:
+ *
+ * NODE_VECTOR_MATH_AVERAGE : 2 -> -1
+ *
+ */
+static void update_vector_math_operators_enum_mapping(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_VECTOR_MATH) {
+ switch (node->custom1) {
+ case 2:
+ node->custom1 = -1;
+ break;
+ case 3:
+ node->custom1 = 7;
+ break;
+ case 5:
+ node->custom1 = 11;
+ break;
+ }
+ }
+ }
+}
+
+/* The Average operator is no longer available in the Vector Math node.
+ * The Vector output was equal to the normalized sum of inputs vectors while
+ * the Value output was equal to the length of the sum of input vectors.
+ * To correct this, we convert the node into an Add node and add a length
+ * or a normalize node if needed.
+ */
+static void update_vector_math_average_operator(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_VECTOR_MATH) {
+ /* See update_vector_math_operators_enum_mapping for the -1. */
+ if (node->custom1 == -1) {
+ node->custom1 = NODE_VECTOR_MATH_ADD;
+ bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
+ if (socket_is_used(sockOutVector)) {
+ bNode *normalizeNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ normalizeNode->custom1 = NODE_VECTOR_MATH_NORMALIZE;
+ normalizeNode->locx = node->locx + node->width + 20.0f;
+ normalizeNode->locy = node->locy;
+ bNodeSocket *sockNormalizeOut = nodeFindSocket(normalizeNode, SOCK_OUT, "Vector");
+
+ /* Iterate backwards from end so we don't encounter newly added links. */
+ for (bNodeLink *link = ntree->links.last; link; link = link->prev) {
+ if (link->fromsock == sockOutVector) {
+ nodeAddLink(ntree, normalizeNode, sockNormalizeOut, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+ bNodeSocket *sockNormalizeA = nodeFindSocket(normalizeNode, SOCK_IN, "A");
+ nodeAddLink(ntree, node, sockOutVector, normalizeNode, sockNormalizeA);
+
+ need_update = true;
+ }
+
+ bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
+ if (socket_is_used(sockOutValue)) {
+ bNode *lengthNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ lengthNode->custom1 = NODE_VECTOR_MATH_LENGTH;
+ lengthNode->locx = node->locx + node->width + 20.0f;
+ if (socket_is_used(sockOutVector)) {
+ lengthNode->locy = node->locy - lengthNode->height - 20.0f;
+ }
+ else {
+ lengthNode->locy = node->locy;
+ }
+ bNodeSocket *sockLengthOut = nodeFindSocket(lengthNode, SOCK_OUT, "Value");
+
+ /* Iterate backwards from end so we don't encounter newly added links. */
+ for (bNodeLink *link = ntree->links.last; link; link = link->prev) {
+ if (link->fromsock == sockOutValue) {
+ nodeAddLink(ntree, lengthNode, sockLengthOut, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+ bNodeSocket *sockLengthA = nodeFindSocket(lengthNode, SOCK_IN, "A");
+ nodeAddLink(ntree, node, sockOutVector, lengthNode, sockLengthA);
+
+ need_update = true;
+ }
+ }
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
+/* The name of the output socket of the Mapping node was changed. So we have to
+ * update it here. The socket's identifier needs to be updated as well since it
+ * is autmatically generated from the name.
+ */
+static void update_mapping_output_name_and_identifier(bNodeTree *ntree)
+{
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_MAPPING) {
+ bNodeSocket *sockResult = node->outputs.first;
+ strcpy(sockResult->name, "Result");
+ strcpy(sockResult->identifier, "Result");
+ }
+ }
+}
+
+/* The Mapping node has been rewritten to support dynamic inputs. Previously,
+ * the transformation information was stored in a TexMapping struct in the
+ * node->storage member of bNode. Currently, the transformation information
+ * is stored in input sockets. To correct this, we transfer the information
+ * from the TexMapping struct to the input sockets.
+ *
+ * Additionally, the Minimum and Maximum properties are no longer available
+ * in the node. To correct this, a Vector Minimum and/or a Vector Maximum
+ * nodes are added if needed.
+ *
+ * Finally, the TexMapping struct is freed and node->storage is set to NULL.
+ */
+static void update_mapping_inputs_and_properties(bNodeTree *ntree)
+{
+ bool need_update = false;
+
+ for (bNode *node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_MAPPING) {
+ TexMapping *mapping = (TexMapping *)node->storage;
+ node->custom1 = mapping->type;
+ node->width = 140.0f;
+
+ bNodeSocket *sockLocation = nodeFindSocket(node, SOCK_IN, "Location");
+ copy_v3_v3(cycles_node_socket_vector_value(sockLocation), mapping->loc);
+ bNodeSocket *sockRotation = nodeFindSocket(node, SOCK_IN, "Rotation");
+ copy_v3_v3(cycles_node_socket_vector_value(sockRotation), mapping->rot);
+ bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale");
+ copy_v3_v3(cycles_node_socket_vector_value(sockScale), mapping->size);
+
+ bNode *maximumNode = NULL;
+ if (mapping->flag & TEXMAP_CLIP_MAX) {
+ maximumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ maximumNode->custom1 = NODE_VECTOR_MATH_MAXIMUM;
+ if (mapping->flag & TEXMAP_CLIP_MIN) {
+ maximumNode->locx = node->locx + (node->width + 20.0f) * 2.0f;
+ }
+ else {
+ maximumNode->locx = node->locx + node->width + 20.0f;
+ }
+ maximumNode->locy = node->locy;
+ bNodeSocket *sockMaximumB = nodeFindSocket(maximumNode, SOCK_IN, "B");
+ copy_v3_v3(cycles_node_socket_vector_value(sockMaximumB), mapping->max);
+ bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Result");
+
+ /* Iterate backwards from end so we don't encounter newly added links. */
+ for (bNodeLink *link = ntree->links.last; link; link = link->prev) {
+ if (link->fromsock == sockMappingResult) {
+ bNodeSocket *sockMaximumResult = nodeFindSocket(maximumNode, SOCK_OUT, "Vector");
+ nodeAddLink(ntree, maximumNode, sockMaximumResult, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+ if (!(mapping->flag & TEXMAP_CLIP_MIN)) {
+ bNodeSocket *sockMaximumA = nodeFindSocket(maximumNode, SOCK_IN, "A");
+ nodeAddLink(ntree, node, sockMappingResult, maximumNode, sockMaximumA);
+ }
+
+ need_update = true;
+ }
+
+ if (mapping->flag & TEXMAP_CLIP_MIN) {
+ bNode *minimumNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+ minimumNode->custom1 = NODE_VECTOR_MATH_MINIMUM;
+ minimumNode->locx = node->locx + node->width + 20.0f;
+ minimumNode->locy = node->locy;
+ bNodeSocket *sockMinimumB = nodeFindSocket(minimumNode, SOCK_IN, "B");
+ copy_v3_v3(cycles_node_socket_vector_value(sockMinimumB), mapping->min);
+
+ bNodeSocket *sockMinimumResult = nodeFindSocket(minimumNode, SOCK_OUT, "Vector");
+ bNodeSocket *sockMappingResult = nodeFindSocket(node, SOCK_OUT, "Result");
+
+ if (maximumNode) {
+ bNodeSocket *sockMaximumA = nodeFindSocket(maximumNode, SOCK_IN, "A");
+ nodeAddLink(ntree, minimumNode, sockMinimumResult, maximumNode, sockMaximumA);
+ }
+ else {
+ /* Iterate backwards from end so we don't encounter newly added links. */
+ for (bNodeLink *link = ntree->links.last; link; link = link->prev) {
+ if (link->fromsock == sockMappingResult) {
+ nodeAddLink(ntree, minimumNode, sockMinimumResult, link->tonode, link->tosock);
+ nodeRemLink(ntree, link);
+ }
+ }
+ }
+ bNodeSocket *sockMinimumA = nodeFindSocket(minimumNode, SOCK_IN, "A");
+ nodeAddLink(ntree, node, sockMappingResult, minimumNode, sockMinimumA);
+
+ need_update = true;
+ }
+
+ MEM_freeN(node->storage);
+ node->storage = NULL;
+ }
+ }
+
+ if (need_update) {
+ ntreeUpdateTree(NULL, ntree);
+ }
+}
+
void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain)
{
/* Particle shape shared with Eevee. */
@@ -417,6 +979,20 @@ void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bm
}
}
}
+
+ if (1) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_math_socket_names_and_identifiers(ntree);
+
+ update_vector_math_socket_names_and_identifiers(ntree);
+ update_vector_math_operators_enum_mapping(ntree);
+
+ update_mapping_output_name_and_identifier(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
}
void do_versions_after_linking_cycles(Main *bmain)
@@ -526,4 +1102,22 @@ void do_versions_after_linking_cycles(Main *bmain)
}
}
}
+
+ if (1) {
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_SHADER) {
+ update_math_single_operand_operators(ntree);
+ update_math_clamp_option(ntree);
+
+ update_vector_math_add_and_subtract_operators(ntree);
+ update_vector_math_dot_product_operator(ntree);
+ update_vector_math_cross_product_operator(ntree);
+ update_vector_math_normalize_operator(ntree);
+ update_vector_math_average_operator(ntree);
+
+ update_mapping_inputs_and_properties(ntree);
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
}
diff --git a/source/blender/compositor/nodes/COM_MathNode.cpp b/source/blender/compositor/nodes/COM_MathNode.cpp
index 5a2f934f37f..d13b34bb6b5 100644
--- a/source/blender/compositor/nodes/COM_MathNode.cpp
+++ b/source/blender/compositor/nodes/COM_MathNode.cpp
@@ -29,61 +29,61 @@ void MathNode::convertToOperations(NodeConverter &converter,
case NODE_MATH_ADD:
operation = new MathAddOperation();
break;
- case NODE_MATH_SUB:
+ case NODE_MATH_SUBTRACT:
operation = new MathSubtractOperation();
break;
- case NODE_MATH_MUL:
+ case NODE_MATH_MULTIPLY:
operation = new MathMultiplyOperation();
break;
case NODE_MATH_DIVIDE:
operation = new MathDivideOperation();
break;
- case NODE_MATH_SIN:
+ case NODE_MATH_SINE:
operation = new MathSineOperation();
break;
- case NODE_MATH_COS:
+ case NODE_MATH_COSINE:
operation = new MathCosineOperation();
break;
- case NODE_MATH_TAN:
+ case NODE_MATH_TANGENT:
operation = new MathTangentOperation();
break;
- case NODE_MATH_ASIN:
+ case NODE_MATH_ARCSINE:
operation = new MathArcSineOperation();
break;
- case NODE_MATH_ACOS:
+ case NODE_MATH_ARCCOSINE:
operation = new MathArcCosineOperation();
break;
- case NODE_MATH_ATAN:
+ case NODE_MATH_ARCTANGENT:
operation = new MathArcTangentOperation();
break;
- case NODE_MATH_POW:
+ case NODE_MATH_POWER:
operation = new MathPowerOperation();
break;
- case NODE_MATH_LOG:
+ case NODE_MATH_LOGARITHM:
operation = new MathLogarithmOperation();
break;
- case NODE_MATH_MIN:
+ case NODE_MATH_MINIMUM:
operation = new MathMinimumOperation();
break;
- case NODE_MATH_MAX:
+ case NODE_MATH_MAXIMUM:
operation = new MathMaximumOperation();
break;
case NODE_MATH_ROUND:
operation = new MathRoundOperation();
break;
- case NODE_MATH_LESS:
+ case NODE_MATH_LESS_THAN:
operation = new MathLessThanOperation();
break;
- case NODE_MATH_GREATER:
+ case NODE_MATH_GREATER_THAN:
operation = new MathGreaterThanOperation();
break;
- case NODE_MATH_MOD:
+ case NODE_MATH_MODULO:
operation = new MathModuloOperation();
break;
- case NODE_MATH_ABS:
+ case NODE_MATH_ABSOLUTE:
operation = new MathAbsoluteOperation();
break;
- case NODE_MATH_ATAN2:
+ case NODE_MATH_ARCTAN2:
operation = new MathArcTan2Operation();
break;
case NODE_MATH_FLOOR:
@@ -92,7 +92,7 @@ void MathNode::convertToOperations(NodeConverter &converter,
case NODE_MATH_CEIL:
operation = new MathCeilOperation();
break;
- case NODE_MATH_FRACT:
+ case NODE_MATH_FRACTION:
operation = new MathFractOperation();
break;
case NODE_MATH_SQRT:
diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c
index ba58dc3d9de..147bb4f957a 100644
--- a/source/blender/draw/intern/draw_cache_impl_mesh.c
+++ b/source/blender/draw/intern/draw_cache_impl_mesh.c
@@ -305,7 +305,7 @@ typedef struct MeshRenderData {
float (*poly_normals)[3];
float *vert_weight;
- char (*vert_color)[3];
+ char (*vert_color)[4];
GPUPackedNormal *poly_normals_pack;
GPUPackedNormal *vert_normals_pack;
bool *edge_select_bool;
@@ -1481,7 +1481,7 @@ static void mesh_render_data_ensure_vert_normals_pack(MeshRenderData *rdata)
/** Ensure #MeshRenderData.vert_color */
static void UNUSED_FUNCTION(mesh_render_data_ensure_vert_color)(MeshRenderData *rdata)
{
- char(*vcol)[3] = rdata->vert_color;
+ char(*vcol)[4] = rdata->vert_color;
if (vcol == NULL) {
if (rdata->edit_bmesh) {
BMesh *bm = rdata->edit_bmesh->bm;
@@ -1504,6 +1504,7 @@ static void UNUSED_FUNCTION(mesh_render_data_ensure_vert_color)(MeshRenderData *
vcol[i][0] = lcol->r;
vcol[i][1] = lcol->g;
vcol[i][2] = lcol->b;
+ vcol[i][3] = lcol->a;
i += 1;
} while ((l_iter = l_iter->next) != l_first);
}
@@ -1520,6 +1521,7 @@ static void UNUSED_FUNCTION(mesh_render_data_ensure_vert_color)(MeshRenderData *
vcol[i][0] = rdata->mloopcol[i].r;
vcol[i][1] = rdata->mloopcol[i].g;
vcol[i][2] = rdata->mloopcol[i].b;
+ vcol[i][3] = rdata->mloopcol[i].a;
}
}
}
@@ -1532,6 +1534,7 @@ fallback:
vcol[i][0] = 255;
vcol[i][1] = 255;
vcol[i][2] = 255;
+ vcol[i][3] = 255;
}
}
@@ -3407,7 +3410,7 @@ static void mesh_create_loop_vcol(MeshRenderData *rdata, GPUVertBuf *vbo)
for (uint i = 0; i < vcol_len; i++) {
const char *attr_name = mesh_render_data_vcol_layer_uuid_get(rdata, i);
vcol_id[i] = GPU_vertformat_attr_add(
- &format, attr_name, GPU_COMP_U8, 3, GPU_FETCH_INT_TO_FLOAT_UNIT);
+ &format, attr_name, GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
/* Auto layer */
if (rdata->cd.layers.auto_vcol[i]) {
attr_name = mesh_render_data_vcol_auto_layer_uuid_get(rdata, i);
@@ -3439,7 +3442,7 @@ static void mesh_create_loop_vcol(MeshRenderData *rdata, GPUVertBuf *vbo)
for (uint j = 0; j < vcol_len; j++) {
const uint layer_offset = rdata->cd.offset.vcol[j];
const uchar *elem = &((MLoopCol *)BM_ELEM_CD_GET_VOID_P(loop, layer_offset))->r;
- copy_v3_v3_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem);
+ copy_v4_v4_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem);
}
}
}
@@ -3449,7 +3452,7 @@ static void mesh_create_loop_vcol(MeshRenderData *rdata, GPUVertBuf *vbo)
for (uint j = 0; j < vcol_len; j++) {
const MLoopCol *layer_data = rdata->cd.layers.vcol[j];
const uchar *elem = &layer_data[loop].r;
- copy_v3_v3_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem);
+ copy_v4_v4_uchar(GPU_vertbuf_raw_step(&vcol_step[j]), elem);
}
}
}
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index 070713ad404..b3df5db32e6 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -603,6 +603,7 @@ static DRWCallState *draw_unit_state_create(void)
state->ob_index = 0;
state->ob_random = 0.0f;
+ copy_v3_fl(state->ob_color, 1.0f);
/* TODO(fclem) get rid of this. */
state->culling = BLI_memblock_alloc(DST.vmempool->cullstates);
diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h
index f37e713e374..85f6cf05e83 100644
--- a/source/blender/draw/intern/draw_manager.h
+++ b/source/blender/draw/intern/draw_manager.h
@@ -101,6 +101,7 @@ enum {
DRW_CALL_MODELVIEWPROJECTION = (1 << 1),
DRW_CALL_ORCOTEXFAC = (1 << 2),
DRW_CALL_OBJECTINFO = (1 << 3),
+ DRW_CALL_OBJECTCOLOR = (1 << 4),
};
typedef struct DRWCullingState {
@@ -122,6 +123,7 @@ typedef struct DRWCallState {
float modelinverse[4][4];
float orcotexfac[2][3];
float ob_random;
+ float ob_color[4];
} DRWCallState;
typedef struct DRWCall {
@@ -196,6 +198,7 @@ struct DRWShadingGroup {
int orcotexfac;
int callid;
int objectinfo;
+ int objectcolor;
uchar matflag; /* Matrices needed, same as DRWCall.flag */
DRWPass *pass_parent; /* backlink to pass we're in */
diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c
index 99ab25645d2..8b7cb9c1dad 100644
--- a/source/blender/draw/intern/draw_manager_data.c
+++ b/source/blender/draw/intern/draw_manager_data.c
@@ -387,6 +387,10 @@ static void drw_call_state_update_matflag(DRWCallState *state,
}
state->ob_random = random * (1.0f / (float)0xFFFFFFFF);
}
+
+ if (new_flags & DRW_CALL_OBJECTCOLOR) {
+ copy_v4_v4(state->ob_color, ob->color);
+ }
}
static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob)
@@ -836,6 +840,7 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
shgroup->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_MVP);
shgroup->orcotexfac = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_ORCO);
shgroup->objectinfo = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_INFO);
+ shgroup->objectcolor = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_OBJECT_COLOR);
shgroup->callid = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_CALLID);
shgroup->matflag = 0;
@@ -851,6 +856,9 @@ static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader)
if (shgroup->objectinfo > -1) {
shgroup->matflag |= DRW_CALL_OBJECTINFO;
}
+ if (shgroup->objectcolor > -1) {
+ shgroup->matflag |= DRW_CALL_OBJECTCOLOR;
+ }
}
static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass)
diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c
index 949d3e1d38b..e3c8f94aa75 100644
--- a/source/blender/draw/intern/draw_manager_exec.c
+++ b/source/blender/draw/intern/draw_manager_exec.c
@@ -571,6 +571,10 @@ static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCall *call)
infos[3] = (state->flag & DRW_CALL_NEGSCALE) ? -1.0f : 1.0f;
GPU_shader_uniform_vector(shgroup->shader, shgroup->objectinfo, 4, 1, (float *)infos);
}
+ if (shgroup->objectcolor != -1) {
+ GPU_shader_uniform_vector(
+ shgroup->shader, shgroup->objectcolor, 4, 1, (float *)state->ob_color);
+ }
if (shgroup->orcotexfac != -1) {
GPU_shader_uniform_vector(
shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)state->orcotexfac);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index e63c8331f18..14a81a73013 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -252,7 +252,6 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA
static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "operation", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "use_clamp", 0, NULL, ICON_NONE);
}
static int node_resize_area_default(bNode *node, int x, int y)
@@ -725,37 +724,7 @@ static void node_buts_image_user(uiLayout *layout,
static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiLayout *row, *col, *sub;
-
- uiItemR(layout, ptr, "vector_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
-
- row = uiLayoutRow(layout, false);
-
- col = uiLayoutColumn(row, true);
- uiItemL(col, IFACE_("Location:"), ICON_NONE);
- uiItemR(col, ptr, "translation", 0, "", ICON_NONE);
-
- col = uiLayoutColumn(row, true);
- uiItemL(col, IFACE_("Rotation:"), ICON_NONE);
- uiItemR(col, ptr, "rotation", 0, "", ICON_NONE);
-
- col = uiLayoutColumn(row, true);
- uiItemL(col, IFACE_("Scale:"), ICON_NONE);
- uiItemR(col, ptr, "scale", 0, "", ICON_NONE);
-
- row = uiLayoutRow(layout, false);
-
- col = uiLayoutColumn(row, true);
- uiItemR(col, ptr, "use_min", 0, IFACE_("Min"), ICON_NONE);
- sub = uiLayoutColumn(col, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min"));
- uiItemR(sub, ptr, "min", 0, "", ICON_NONE);
-
- col = uiLayoutColumn(row, true);
- uiItemR(col, ptr, "use_max", 0, IFACE_("Max"), ICON_NONE);
- sub = uiLayoutColumn(col, true);
- uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max"));
- uiItemR(sub, ptr, "max", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "vector_type", 0, NULL, ICON_NONE);
}
static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -932,14 +901,24 @@ static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), Poi
static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "dimensions", 0, "", ICON_NONE);
uiItemR(layout, ptr, "musgrave_type", 0, "", ICON_NONE);
}
static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiItemR(layout, ptr, "coloring", 0, "", ICON_NONE);
- uiItemR(layout, ptr, "distance", 0, "", ICON_NONE);
+ uiItemR(layout, ptr, "dimensions", 0, "", ICON_NONE);
uiItemR(layout, ptr, "feature", 0, "", ICON_NONE);
+ int feature = RNA_enum_get(ptr, "feature");
+ if (feature != SHD_VORONOI_DISTANCE_TO_EDGE && feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ RNA_enum_get(ptr, "dimensions") != 1) {
+ uiItemR(layout, ptr, "distance", 0, "", ICON_NONE);
+ }
+}
+
+static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "dimensions", 0, "", ICON_NONE);
}
static void node_shader_buts_tex_pointdensity(uiLayout *layout,
@@ -1012,6 +991,18 @@ static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *pt
}
}
+static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ PointerRNA obptr = CTX_data_pointer_get(C, "active_object");
+ if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) {
+ PointerRNA dataptr = RNA_pointer_get(&obptr, "data");
+ uiItemPointerR(layout, ptr, "layer_name", &dataptr, "vertex_colors", "", ICON_GROUP_VCOL);
+ }
+ else {
+ uiItemL(layout, "No mesh in active object.", ICON_ERROR);
+ }
+}
+
static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "use_tips", 0, NULL, 0);
@@ -1181,6 +1172,11 @@ static void node_shader_buts_ambient_occlusion(uiLayout *layout,
uiItemR(layout, ptr, "only_local", 0, NULL, ICON_NONE);
}
+static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "dimensions", 0, "", ICON_NONE);
+}
+
/* only once called */
static void node_shader_set_butfunc(bNodeType *ntype)
{
@@ -1212,7 +1208,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_MATH:
ntype->draw_buttons = node_buts_math;
break;
- case SH_NODE_VECT_MATH:
+ case SH_NODE_VECTOR_MATH:
ntype->draw_buttons = node_shader_buts_vect_math;
break;
case SH_NODE_VECT_TRANSFORM:
@@ -1253,6 +1249,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_TEX_VORONOI:
ntype->draw_buttons = node_shader_buts_tex_voronoi;
break;
+ case SH_NODE_TEX_NOISE:
+ ntype->draw_buttons = node_shader_buts_tex_noise;
+ break;
case SH_NODE_TEX_POINTDENSITY:
ntype->draw_buttons = node_shader_buts_tex_pointdensity;
break;
@@ -1302,6 +1301,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_UVMAP:
ntype->draw_buttons = node_shader_buts_uvmap;
break;
+ case SH_NODE_VERTEX_COLOR:
+ ntype->draw_buttons = node_shader_buts_vertex_color;
+ break;
case SH_NODE_UVALONGSTROKE:
ntype->draw_buttons = node_shader_buts_uvalongstroke;
break;
@@ -1322,6 +1324,9 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_AMBIENT_OCCLUSION:
ntype->draw_buttons = node_shader_buts_ambient_occlusion;
break;
+ case SH_NODE_TEX_WHITE_NOISE:
+ ntype->draw_buttons = node_shader_buts_white_noise;
+ break;
}
}
@@ -3333,7 +3338,13 @@ static void std_node_socket_draw(
uiItemR(layout, ptr, "default_value", 0, text, 0);
break;
case SOCK_VECTOR:
- uiTemplateComponentMenu(layout, ptr, "default_value", text);
+ if (sock->flag & SOCK_COMPACT) {
+ uiTemplateComponentMenu(layout, ptr, "default_value", text);
+ }
+ else {
+ uiLayout *column = uiLayoutColumn(layout, true);
+ uiItemR(column, ptr, "default_value", 0, text, 0);
+ }
break;
case SOCK_RGBA:
case SOCK_STRING: {
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index dd5292d9c58..2e0dc750e46 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -92,7 +92,7 @@ typedef enum eGPUBuiltin {
GPU_INVERSE_OBJECT_MATRIX = (1 << 3),
GPU_VIEW_POSITION = (1 << 4),
GPU_VIEW_NORMAL = (1 << 5),
- GPU_OBCOLOR = (1 << 6),
+ GPU_OBJECT_COLOR = (1 << 6),
GPU_AUTO_BUMPSCALE = (1 << 7),
GPU_CAMERA_TEXCO_FACTORS = (1 << 8),
GPU_PARTICLE_SCALAR_PROPS = (1 << 9),
diff --git a/source/blender/gpu/GPU_shader_interface.h b/source/blender/gpu/GPU_shader_interface.h
index d3a9a18b392..ec97e1b085e 100644
--- a/source/blender/gpu/GPU_shader_interface.h
+++ b/source/blender/gpu/GPU_shader_interface.h
@@ -48,9 +48,10 @@ typedef enum {
GPU_UNIFORM_ORCO, /* vec3 OrcoTexCoFactors[] */
GPU_UNIFORM_CLIPPLANES, /* vec4 WorldClipPlanes[] */
- GPU_UNIFORM_COLOR, /* vec4 color */
- GPU_UNIFORM_CALLID, /* int callId */
- GPU_UNIFORM_OBJECT_INFO, /* vec3 objectInfo */
+ GPU_UNIFORM_COLOR, /* vec4 color */
+ GPU_UNIFORM_CALLID, /* int callId */
+ GPU_UNIFORM_OBJECT_INFO, /* vec3 objectInfo */
+ GPU_UNIFORM_OBJECT_COLOR, /* vec4 objectColor */
GPU_UNIFORM_CUSTOM, /* custom uniform, not one of the above built-ins */
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 51b73c93c86..43924f6d664 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -541,8 +541,8 @@ const char *GPU_builtin_name(eGPUBuiltin builtin)
else if (builtin == GPU_VIEW_NORMAL) {
return "varnormal";
}
- else if (builtin == GPU_OBCOLOR) {
- return "unfobcolor";
+ else if (builtin == GPU_OBJECT_COLOR) {
+ return "unfobjectcolor";
}
else if (builtin == GPU_AUTO_BUMPSCALE) {
return "unfobautobumpscale";
@@ -1075,11 +1075,11 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u
BLI_dynstr_append(ds,
"#define USE_ATTR\n"
- "vec3 srgb_to_linear_attr(vec3 c) {\n"
- "\tc = max(c, vec3(0.0));\n"
- "\tvec3 c1 = c * (1.0 / 12.92);\n"
- "\tvec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));\n"
- "\treturn mix(c1, c2, step(vec3(0.04045), c));\n"
+ "vec4 srgb_to_linear_attr(vec4 c) {\n"
+ "\tc = max(c, vec4(0.0));\n"
+ "\tvec4 c1 = c * (1.0 / 12.92);\n"
+ "\tvec4 c2 = pow((c + 0.055) * (1.0 / 1.055), vec4(2.4));\n"
+ "\treturn mix(c1, c2, step(vec4(0.04045), c));\n"
"}\n\n");
/* Prototype because defined later. */
diff --git a/source/blender/gpu/intern/gpu_shader_interface.c b/source/blender/gpu/intern/gpu_shader_interface.c
index e34c6e23024..f205ef31ed2 100644
--- a/source/blender/gpu/intern/gpu_shader_interface.c
+++ b/source/blender/gpu/intern/gpu_shader_interface.c
@@ -67,6 +67,7 @@ static const char *BuiltinUniform_name(GPUUniformBuiltin u)
[GPU_UNIFORM_COLOR] = "color",
[GPU_UNIFORM_CALLID] = "callId",
[GPU_UNIFORM_OBJECT_INFO] = "unfobjectinfo",
+ [GPU_UNIFORM_OBJECT_COLOR] = "unfobjectcolor",
[GPU_UNIFORM_CUSTOM] = NULL,
[GPU_NUM_UNIFORMS] = NULL,
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 00b8ce54eb3..69e01882d50 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -235,7 +235,7 @@ void point_map_to_tube(vec3 vin, out vec3 vout)
vout = vec3(u, v, 0.0);
}
-void mapping(
+void mapping_mat4(
vec3 vec, vec4 m0, vec4 m1, vec4 m2, vec4 m3, vec3 minvec, vec3 maxvec, out vec3 outvec)
{
mat4 mat = mat4(m0, m1, m2, m3);
@@ -243,6 +243,83 @@ void mapping(
outvec = clamp(outvec, minvec, maxvec);
}
+vec3 safe_divide(vec3 a, vec3 b)
+{
+ return vec3((b.x != 0.0) ? a.x / b.x : 0.0,
+ (b.y != 0.0) ? a.y / b.y : 0.0,
+ (b.z != 0.0) ? a.z / b.z : 0.0);
+}
+
+float safe_divide(float a, float b)
+{
+ return (b != 0.0) ? a / b : 0.0;
+}
+
+vec2 safe_divide(vec2 a, float b)
+{
+ return vec2((b != 0.0) ? a.x / b : 0.0, (b != 0.0) ? a.y / b : 0.0);
+}
+
+vec3 safe_divide(vec3 a, float b)
+{
+ return vec3((b != 0.0) ? a.x / b : 0.0, (b != 0.0) ? a.y / b : 0.0, (b != 0.0) ? a.z / b : 0.0);
+}
+
+vec4 safe_divide(vec4 a, float b)
+{
+ return vec4((b != 0.0) ? a.x / b : 0.0,
+ (b != 0.0) ? a.y / b : 0.0,
+ (b != 0.0) ? a.z / b : 0.0,
+ (b != 0.0) ? a.w / b : 0.0);
+}
+
+mat3 euler_to_mat3(vec3 euler)
+{
+ mat3 mat;
+ float cx, cy, cz, sx, sy, sz;
+
+ cx = cos(euler.x);
+ cy = cos(euler.y);
+ cz = cos(euler.z);
+ sx = sin(euler.x);
+ sy = sin(euler.y);
+ sz = sin(euler.z);
+
+ mat[0][0] = cy * cz;
+ mat[0][1] = cx * sz + cz * sx * sy;
+ mat[0][2] = sx * sz - cx * cz * sy;
+
+ mat[1][0] = -cy * sz;
+ mat[1][1] = cx * cz - sx * sy * sz;
+ mat[1][2] = cz * sx + cx * sy * sz;
+
+ mat[2][0] = sy;
+ mat[2][1] = -cy * sx;
+ mat[2][2] = cx * cy;
+
+ return mat;
+}
+
+void mapping_point(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+ result = (euler_to_mat3(rotation) * (vector * scale)) + location;
+}
+
+void mapping_texture(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+ result = safe_divide(euler_to_mat3(-rotation) * (vector - location), scale);
+}
+
+void mapping_vector(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+ result = euler_to_mat3(rotation) * (vector * scale);
+}
+
+void mapping_normal(vec3 vector, vec3 location, vec3 rotation, vec3 scale, out vec3 result)
+{
+ result = normalize(euler_to_mat3(rotation) * safe_divide(vector, scale));
+}
+
void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
{
outdepth = abs(co.z);
@@ -250,225 +327,264 @@ void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
outview = normalize(co);
}
-void math_add(float val1, float val2, out float outval)
+void math_add(float a, float b, out float result)
{
- outval = val1 + val2;
+ result = a + b;
}
-void math_subtract(float val1, float val2, out float outval)
+void math_subtract(float a, float b, out float result)
{
- outval = val1 - val2;
+ result = a - b;
}
-void math_multiply(float val1, float val2, out float outval)
+void math_multiply(float a, float b, out float result)
{
- outval = val1 * val2;
+ result = a * b;
}
-void math_divide(float val1, float val2, out float outval)
+void math_divide(float a, float b, out float result)
{
- if (val2 == 0.0) {
- outval = 0.0;
+ result = (b != 0.0) ? a / b : 0.0;
+}
+
+void math_power(float a, float b, out float result)
+{
+ if (a >= 0.0) {
+ result = compatible_pow(a, b);
}
else {
- outval = val1 / val2;
+ float fraction = mod(abs(b), 1.0);
+ if (fraction > 0.999 || fraction < 0.001) {
+ result = compatible_pow(a, floor(b + 0.5));
+ }
+ else {
+ result = 0.0;
+ }
}
}
-void math_sine(float val, out float outval)
+void math_logarithm(float a, float b, out float result)
{
- outval = sin(val);
+ result = (a > 0.0 && b > 0.0) ? log2(a) / log2(b) : 0.0;
}
-void math_cosine(float val, out float outval)
+void math_sqrt(float a, float b, out float result)
{
- outval = cos(val);
+ result = (a > 0.0) ? sqrt(a) : 0.0;
}
-void math_tangent(float val, out float outval)
+void math_absolute(float a, float b, out float result)
{
- outval = tan(val);
+ result = abs(a);
}
-void math_asin(float val, out float outval)
+void math_minimum(float a, float b, out float result)
{
- if (val <= 1.0 && val >= -1.0) {
- outval = asin(val);
- }
- else {
- outval = 0.0;
- }
+ result = min(a, b);
}
-void math_acos(float val, out float outval)
+void math_maximum(float a, float b, out float result)
{
- if (val <= 1.0 && val >= -1.0) {
- outval = acos(val);
- }
- else {
- outval = 0.0;
- }
+ result = max(a, b);
}
-void math_atan(float val, out float outval)
+void math_less_than(float a, float b, out float result)
{
- outval = atan(val);
+ result = (a < b) ? 1.0 : 0.0;
}
-void math_pow(float val1, float val2, out float outval)
+void math_greater_than(float a, float b, out float result)
{
- if (val1 >= 0.0) {
- outval = compatible_pow(val1, val2);
- }
- else {
- float val2_mod_1 = mod(abs(val2), 1.0);
+ result = (a > b) ? 1.0 : 0.0;
+}
- if (val2_mod_1 > 0.999 || val2_mod_1 < 0.001) {
- outval = compatible_pow(val1, floor(val2 + 0.5));
- }
- else {
- outval = 0.0;
- }
- }
+void math_round(float a, float b, out float result)
+{
+ result = floor(a + 0.5);
}
-void math_log(float val1, float val2, out float outval)
+void math_floor(float a, float b, out float result)
{
- if (val1 > 0.0 && val2 > 0.0) {
- outval = log2(val1) / log2(val2);
- }
- else {
- outval = 0.0;
- }
+ result = floor(a);
}
-void math_max(float val1, float val2, out float outval)
+void math_ceil(float a, float b, out float result)
{
- outval = max(val1, val2);
+ result = ceil(a);
}
-void math_min(float val1, float val2, out float outval)
+void math_fraction(float a, float b, out float result)
{
- outval = min(val1, val2);
+ result = a - floor(a);
}
-void math_round(float val, out float outval)
+void math_modulo(float a, float b, out float result)
{
- outval = floor(val + 0.5);
+ /* Change sign to match C convention, mod in GLSL will take absolute for negative numbers.
+ * See https://www.opengl.org/sdk/docs/man/html/mod.xhtml
+ */
+ result = (b != 0.0) ? sign(a) * mod(abs(a), b) : 0.0;
}
-void math_less_than(float val1, float val2, out float outval)
+void math_sine(float a, float b, out float result)
{
- if (val1 < val2) {
- outval = 1.0;
- }
- else {
- outval = 0.0;
- }
+ result = sin(a);
}
-void math_greater_than(float val1, float val2, out float outval)
+void math_cosine(float a, float b, out float result)
{
- if (val1 > val2) {
- outval = 1.0;
- }
- else {
- outval = 0.0;
- }
+ result = cos(a);
}
-void math_modulo(float val1, float val2, out float outval)
+void math_tangent(float a, float b, out float result)
{
- if (val2 == 0.0) {
- outval = 0.0;
- }
- else {
- /* change sign to match C convention, mod in GLSL will take absolute for negative numbers,
- * see https://www.opengl.org/sdk/docs/man/html/mod.xhtml */
- outval = sign(val1) * mod(abs(val1), val2);
- }
+ result = tan(a);
}
-void math_abs(float val1, out float outval)
+void math_arcsine(float a, float b, out float result)
{
- outval = abs(val1);
+ result = (a <= 1.0 && a >= -1.0) ? asin(a) : 0.0;
}
-void math_atan2(float val1, float val2, out float outval)
+void math_arccosine(float a, float b, out float result)
{
- outval = atan(val1, val2);
+ result = (a <= 1.0 && a >= -1.0) ? acos(a) : 0.0;
}
-void math_floor(float val, out float outval)
+void math_arctangent(float a, float b, out float result)
{
- outval = floor(val);
+ result = atan(a);
}
-void math_ceil(float val, out float outval)
+void math_arctan2(float a, float b, out float result)
{
- outval = ceil(val);
+ result = atan(a, b);
}
-void math_fract(float val, out float outval)
+void squeeze(float val, float width, float center, out float outval)
{
- outval = val - floor(val);
+ outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width)));
}
-void math_sqrt(float val, out float outval)
+void map_range(
+ float value, float fromMin, float fromMax, float toMin, float toMax, out float result)
{
- if (val > 0.0) {
- outval = sqrt(val);
+ if (fromMax != fromMin) {
+ result = toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin);
}
else {
- outval = 0.0;
+ result = 0.0;
}
}
-void squeeze(float val, float width, float center, out float outval)
+void vec_math_add(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
- outval = 1.0 / (1.0 + pow(2.71828183, -((val - center) * width)));
+ outVector = a + b;
+}
+
+void vec_math_subtract(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = a - b;
}
-void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
+void vec_math_multiply(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
- outvec = v1 + v2;
- outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333;
+ outVector = a * b;
}
-void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
+void vec_math_divide(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
- outvec = v1 - v2;
- outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333;
+ outVector = safe_divide(a, b);
}
-void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
+void vec_math_cross(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
- outvec = v1 + v2;
- outval = length(outvec);
- outvec = normalize(outvec);
+ outVector = cross(a, b);
}
-void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec)
+
+void vec_math_project(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
- outvec = strength * v1 + (1 - strength) * v2;
+ float lenSquared = dot(b, b);
+ outVector = (lenSquared != 0.0) ? (dot(a, b) / lenSquared) * b : vec3(0.0);
}
-void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
+void vec_math_reflect(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
- outvec = vec3(0);
- outval = dot(v1, v2);
+ outVector = reflect(a, normalize(b));
}
-void vec_math_cross(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
+void vec_math_dot(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
- outvec = cross(v1, v2);
- outval = length(outvec);
- outvec /= outval;
+ outValue = dot(a, b);
}
-void vec_math_normalize(vec3 v, out vec3 outvec, out float outval)
+void vec_math_distance(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
{
- outval = length(v);
- outvec = normalize(v);
+ outValue = distance(a, b);
+}
+
+void vec_math_length(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outValue = length(a);
+}
+
+void vec_math_scale(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = a * scale;
+}
+
+void vec_math_normalize(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = normalize(a);
+}
+
+void vec_math_snap(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector.x = (b.x != 0.0) ? floor(a.x / b.x) * b.x : 0.0;
+ outVector.y = (b.y != 0.0) ? floor(a.y / b.y) * b.y : 0.0;
+ outVector.z = (b.z != 0.0) ? floor(a.z / b.z) * b.z : 0.0;
+}
+
+void vec_math_floor(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = floor(a);
+}
+
+void vec_math_ceil(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = ceil(a);
+}
+
+void vec_math_modulo(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ math_modulo(a.x, b.x, outVector.x);
+ math_modulo(a.y, b.y, outVector.y);
+ math_modulo(a.z, b.z, outVector.z);
+}
+
+void vec_math_fraction(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = fract(a);
+}
+
+void vec_math_absolute(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = abs(a);
+}
+
+void vec_math_minimum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = min(a, b);
+}
+
+void vec_math_maximum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+ outVector = max(a, b);
+}
+
+void vec_math_mix(float strength, vec3 a, vec3 b, out vec3 outVector)
+{
+ outVector = strength * a + (1 - strength) * b;
}
void vec_math_negate(vec3 v, out vec3 outv)
@@ -960,9 +1076,9 @@ void clamp_vec3(vec3 vec, vec3 min, vec3 max, out vec3 out_vec)
out_vec = clamp(vec, min, max);
}
-void clamp_val(float value, float min, float max, out float out_value)
+void clamp_value(float value, float min, float max, out float result)
{
- out_value = clamp(value, min, max);
+ result = clamp(value, min, max);
}
void hue_sat(float hue, float sat, float value, float fac, vec4 col, out vec4 outcol)
@@ -1123,9 +1239,34 @@ float integer_noise(int n)
return 0.5 * (float(nn) / 1073741824.0);
}
-uint hash(uint kx, uint ky, uint kz)
-{
+/* ***** Jenkins Lookup3 Hash Functions ***** */
+
+/* Source: http://burtleburtle.net/bob/c/lookup3.c */
+
#define rot(x, k) (((x) << (k)) | ((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; \
@@ -1143,9 +1284,34 @@ uint hash(uint kx, uint ky, uint kz)
c ^= b; \
c -= rot(b, 24); \
}
- // now hash the data!
- uint a, b, c, len = 3u;
- a = b = c = 0xdeadbeefu + (len << 2u) + 13u;
+
+uint hash_uint(uint kx)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeefu + (1u << 2u) + 13u;
+
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+uint hash_uint2(uint kx, uint ky)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeefu + (2u << 2u) + 13u;
+
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+}
+
+uint hash_uint3(uint kx, uint ky, uint kz)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeefu + (3u << 2u) + 13u;
c += kz;
b += ky;
@@ -1153,36 +1319,147 @@ uint hash(uint kx, uint ky, uint kz)
final(a, b, c);
return c;
+}
+
+uint hash_uint4(uint kx, uint ky, uint kz, uint kw)
+{
+ uint a, b, c;
+ a = b = c = 0xdeadbeefu + (4u << 2u) + 13u;
+
+ a += kx;
+ b += ky;
+ c += kz;
+ mix(a, b, c);
+
+ a += kw;
+ final(a, b, c);
+
+ return c;
+}
+
#undef rot
#undef final
+#undef mix
+
+uint hash_int(int kx)
+{
+ return hash_uint(uint(kx));
}
-uint hash(int kx, int ky, int kz)
+uint hash_int2(int kx, int ky)
{
- return hash(uint(kx), uint(ky), uint(kz));
+ return hash_uint2(uint(kx), uint(ky));
}
-float bits_to_01(uint bits)
+uint hash_int3(int kx, int ky, int kz)
{
- return (float(bits) / 4294967295.0);
+ return hash_uint3(uint(kx), uint(ky), uint(kz));
}
-float cellnoise(vec3 p)
+uint hash_int4(int kx, int ky, int kz, int kw)
{
- int ix = quick_floor(p.x);
- int iy = quick_floor(p.y);
- int iz = quick_floor(p.z);
+ return hash_uint4(uint(kx), uint(ky), uint(kz), uint(kw));
+}
- return bits_to_01(hash(uint(ix), uint(iy), uint(iz)));
+/* Hashing uint or uint[234] into a float in the range [0, 1]. */
+
+float hash_uint_to_float(uint kx)
+{
+ return float(hash_uint(kx)) / float(0xFFFFFFFFu);
+}
+
+float hash_uint2_to_float(uint kx, uint ky)
+{
+ return float(hash_uint2(kx, ky)) / float(0xFFFFFFFFu);
+}
+
+float hash_uint3_to_float(uint kx, uint ky, uint kz)
+{
+ return float(hash_uint3(kx, ky, kz)) / float(0xFFFFFFFFu);
+}
+
+float hash_uint4_to_float(uint kx, uint ky, uint kz, uint kw)
+{
+ return float(hash_uint4(kx, ky, kz, kw)) / float(0xFFFFFFFFu);
+}
+
+/* Hashing float or vec[234] into a float in the range [0, 1]. */
+
+float hash_float_to_float(float k)
+{
+ return hash_uint_to_float(floatBitsToUint(k));
}
-vec3 cellnoise_color(vec3 p)
+float hash_vec2_to_float(vec2 k)
{
- float r = cellnoise(p.xyz);
- float g = cellnoise(p.yxz);
- float b = cellnoise(p.yzx);
+ return hash_uint2_to_float(floatBitsToUint(k.x), floatBitsToUint(k.y));
+}
+
+float hash_vec3_to_float(vec3 k)
+{
+ return hash_uint3_to_float(floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z));
+}
+
+float hash_vec4_to_float(vec4 k)
+{
+ return hash_uint4_to_float(
+ floatBitsToUint(k.x), floatBitsToUint(k.y), floatBitsToUint(k.z), floatBitsToUint(k.w));
+}
+
+/* Hashing vec[234] into vec[234] of components in the range [0, 1]. */
- return vec3(r, g, b);
+vec2 hash_vec2_to_vec2(vec2 k)
+{
+ return vec2(hash_vec2_to_float(k), hash_vec3_to_float(vec3(k, 1.0)));
+}
+
+vec3 hash_vec3_to_vec3(vec3 k)
+{
+ return vec3(hash_vec3_to_float(k), hash_vec4_to_float(vec4(k, 1.0)), hash_vec4_to_float(vec4(k, 2.0)));
+}
+
+vec4 hash_vec4_to_vec4(vec4 k)
+{
+ return vec4(hash_vec4_to_float(k.xyzw), hash_vec4_to_float(k.wxyz), hash_vec4_to_float(k.zwxy), hash_vec4_to_float(k.yzwx));
+}
+
+/* Hashing float or vec[234] into vec3 of components in range [0, 1]. */
+
+vec3 hash_float_to_vec3(float k)
+{
+ return vec3(hash_float_to_float(k), hash_vec2_to_float(vec2(k, 1.0)), hash_vec2_to_float(vec2(k, 2.0)));
+}
+
+vec3 hash_vec2_to_vec3(vec2 k)
+{
+ return vec3(hash_vec2_to_float(k), hash_vec3_to_float(vec3(k, 1.0)), hash_vec3_to_float(vec3(k, 2.0)));
+}
+
+vec3 hash_vec4_to_vec3(vec4 k)
+{
+ return vec3(hash_vec4_to_float(k.xyzw), hash_vec4_to_float(k.zxwy), hash_vec4_to_float(k.wzyx));
+}
+
+/* White Noise */
+
+void node_white_noise_1d(vec3 vector, float w, out float value)
+{
+ value = hash_float_to_float(w);
+}
+
+void node_white_noise_2d(vec3 vector, float w, out float value)
+{
+ value = hash_vec2_to_float(vector.xy);
+}
+
+void node_white_noise_3d(vec3 vector, float w, out float value)
+{
+ value = hash_vec3_to_float(vector);
+}
+
+void node_white_noise_4d(vec3 vector, float w, out float value)
+{
+ value = hash_vec4_to_float(vec4(vector, w));
}
float floorfrac(float x, out int i)
@@ -2074,11 +2351,40 @@ void node_attribute_volume_temperature(
outcol = vec4(outf, outf, outf, 1.0);
}
-void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
+void node_volume_info(sampler3D densitySampler,
+ sampler3D flameSampler,
+ vec2 temperature,
+ out vec4 outColor,
+ out float outDensity,
+ out float outFlame,
+ out float outTemprature)
+{
+#if defined(MESH_SHADER) && defined(VOLUMETRICS)
+ vec3 p = volumeObjectLocalCoord;
+#else
+ vec3 p = vec3(0.0);
+#endif
+
+ vec4 density = texture(densitySampler, p);
+ outDensity = density.a;
+
+ /* Density is premultiplied for interpolation, divide it out here. */
+ if (density.a > 1e-8) {
+ density.rgb /= density.a;
+ }
+ outColor = vec4(density.rgb * volumeColor, 1.0);
+
+ float flame = texture(flameSampler, p).r;
+ outFlame = flame;
+
+ outTemprature = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0;
+}
+
+void node_attribute(vec4 attr, out vec4 outcol, out vec3 outvec, out float outfac)
{
- outcol = vec4(attr, 1.0);
- outvec = attr;
- outf = dot(vec3(1.0 / 3.0), attr);
+ outcol = attr;
+ outvec = attr.xyz;
+ outfac = dot(vec3(1.0 / 3.0), attr.xyz);
}
void node_uvmap(vec3 attr_uv, out vec3 outvec)
@@ -2086,6 +2392,12 @@ void node_uvmap(vec3 attr_uv, out vec3 outvec)
outvec = attr_uv;
}
+void node_vertex_color(vec4 vertexColor, out vec4 outColor, out float outAlpha)
+{
+ outColor = vertexColor;
+ outAlpha = vertexColor.a;
+}
+
void tangent_orco_x(vec3 orco_in, out vec3 orco_out)
{
orco_out = orco_in.xzy * vec3(0.0, -0.5, 0.5) + vec3(0.0, 0.25, -0.25);
@@ -2806,19 +3118,97 @@ void node_tex_magic(
fac = (color.x + color.y + color.z) / 3.0;
}
+/* **** Perlin Noise **** */
+
+/* The following functions compute 1D, 2D, 3D, and 4D perlin noise.
+ * The code is based on the OSL noise code for compatibility.
+ * See oslnoise.h
+ */
+
+/* Bilinear Interpolation:
+ *
+ * v2 v3
+ * @ + + + + @ y
+ * + + ^
+ * + + |
+ * + + |
+ * @ + + + + @ @------> x
+ * v0 v1
+ *
+ */
+float bi_mix(float v0, float v1, float v2, float v3, float x, float y)
+{
+ float x1 = 1.0 - x;
+ return (1.0 - y) * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x);
+}
+
+/* Trilinear Interpolation:
+ *
+ * v6 v7
+ * @ + + + + + + @
+ * +\ +\
+ * + \ + \
+ * + \ + \
+ * + \ v4 + \ v5
+ * + @ + + + +++ + @ z
+ * + + + + y ^
+ * v2 @ + +++ + + + @ v3 + \ |
+ * \ + \ + \ |
+ * \ + \ + \|
+ * \ + \ + +---------> x
+ * \+ \+
+ * @ + + + + + + @
+ * v0 v1
+ */
+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)
+{
+ float x1 = 1.0 - x;
+ float y1 = 1.0 - y;
+ float z1 = 1.0 - z;
+ return z1 * (y1 * (v0 * x1 + v1 * x) + y * (v2 * x1 + v3 * x)) +
+ z * (y1 * (v4 * x1 + v5 * x) + y * (v6 * x1 + v7 * x));
+}
+
+/* An alternative to Hermite interpolation that have zero first and
+ * second derivatives at t = 0 and t = 1.
+ * Described in Ken Perlin's "Improving noise" [2002].
+ */
float noise_fade(float t)
{
return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
}
-float noise_scale3(float result)
+float negate_if(float val, uint condition)
{
- return 0.9820 * result;
+ return (condition != 0u) ? -val : val;
}
-float noise_nerp(float t, float a, float b)
+/* Compute the dot product with a randomly choose vector from a list of
+ * predetermined vectors based on a hash value.
+ */
+float noise_grad(uint hash, float x)
{
- return (1.0 - t) * a + t * b;
+ uint h = hash & 15u;
+ float g = 1u + (h & 7u);
+ return negate_if(g, h & 8u) * x;
+}
+
+float noise_grad(uint hash, float x, float y)
+{
+ uint h = hash & 7u;
+ float u = h < 4u ? x : y;
+ float v = 2.0 * (h < 4u ? y : x);
+ return negate_if(u, h & 1u) + negate_if(v, h & 2u);
}
float noise_grad(uint hash, float x, float y, float z)
@@ -2827,59 +3217,276 @@ float noise_grad(uint hash, float x, float y, float z)
float u = h < 8u ? x : y;
float vt = ((h == 12u) || (h == 14u)) ? x : z;
float v = h < 4u ? y : vt;
- return (((h & 1u) != 0u) ? -u : u) + (((h & 2u) != 0u) ? -v : v);
+ return negate_if(u, h & 1u) + negate_if(v, h & 2u);
+}
+
+float noise_grad(uint hash, float x, float y, float z, float w)
+{
+ uint h = hash & 31u;
+ float u = h < 24u ? x : y;
+ float v = h < 16u ? y : z;
+ float s = h < 8u ? z : w;
+ return negate_if(u, h & 1u) + negate_if(v, h & 2u) + negate_if(s, h & 4u);
}
-float noise_perlin(float x, float y, float z)
+float noise_perlin(float x)
{
int X;
float fx = floorfrac(x, X);
+ float u = noise_fade(fx);
+
+ float r = mix(noise_grad(hash_int(X), fx), noise_grad(hash_int(X + 1), fx - 1.0), u);
+
+ return r;
+}
+
+float noise_perlin(vec2 vec)
+{
+ int X;
+ int Y;
+
+ float fx = floorfrac(vec.x, X);
+ float fy = floorfrac(vec.y, Y);
+
+ float u = noise_fade(fx);
+ float v = noise_fade(fy);
+
+ float r = bi_mix(noise_grad(hash_int2(X, Y), fx, fy),
+ noise_grad(hash_int2(X + 1, Y), fx - 1.0, fy),
+ noise_grad(hash_int2(X, Y + 1), fx, fy - 1.0),
+ noise_grad(hash_int2(X + 1, Y + 1), fx - 1.0, fy - 1.0),
+ u,
+ v);
+
+ return r;
+}
+
+float noise_perlin(vec3 vec)
+{
+ int X;
int Y;
- float fy = floorfrac(y, Y);
int Z;
- float fz = floorfrac(z, Z);
+
+ float fx = floorfrac(vec.x, X);
+ float fy = floorfrac(vec.y, Y);
+ float fz = floorfrac(vec.z, Z);
float u = noise_fade(fx);
float v = noise_fade(fy);
float w = noise_fade(fz);
- float noise_u[2], noise_v[2];
+ float r = tri_mix(noise_grad(hash_int3(X, Y, Z), fx, fy, fz),
+ noise_grad(hash_int3(X + 1, Y, Z), fx - 1, fy, fz),
+ noise_grad(hash_int3(X, Y + 1, Z), fx, fy - 1, fz),
+ noise_grad(hash_int3(X + 1, Y + 1, Z), fx - 1, fy - 1, fz),
+ noise_grad(hash_int3(X, Y, Z + 1), fx, fy, fz - 1),
+ noise_grad(hash_int3(X + 1, Y, Z + 1), fx - 1, fy, fz - 1),
+ noise_grad(hash_int3(X, Y + 1, Z + 1), fx, fy - 1, fz - 1),
+ noise_grad(hash_int3(X + 1, Y + 1, Z + 1), fx - 1, fy - 1, fz - 1),
+ u,
+ v,
+ w);
- noise_u[0] = noise_nerp(
- u, noise_grad(hash(X, Y, Z), fx, fy, fz), noise_grad(hash(X + 1, Y, Z), fx - 1.0, fy, fz));
+ return r;
+}
- noise_u[1] = noise_nerp(u,
- noise_grad(hash(X, Y + 1, Z), fx, fy - 1.0, fz),
- noise_grad(hash(X + 1, Y + 1, Z), fx - 1.0, fy - 1.0, fz));
+float noise_perlin(vec4 vec)
+{
+ int X;
+ int Y;
+ int Z;
+ int W;
- noise_v[0] = noise_nerp(v, noise_u[0], noise_u[1]);
+ float fx = floorfrac(vec.x, X);
+ float fy = floorfrac(vec.y, Y);
+ float fz = floorfrac(vec.z, Z);
+ float fw = floorfrac(vec.w, W);
- noise_u[0] = noise_nerp(u,
- noise_grad(hash(X, Y, Z + 1), fx, fy, fz - 1.0),
- noise_grad(hash(X + 1, Y, Z + 1), fx - 1.0, fy, fz - 1.0));
+ float u = noise_fade(fx);
+ float v = noise_fade(fy);
+ float t = noise_fade(fz);
+ float s = noise_fade(fw);
+
+ float r = mix(
+ tri_mix(noise_grad(hash_int4(X, Y, Z, W), fx, fy, fz, fw),
+ noise_grad(hash_int4(X + 1, Y, Z, W), fx - 1.0, fy, fz, fw),
+ noise_grad(hash_int4(X, Y + 1, Z, W), fx, fy - 1.0, fz, fw),
+ noise_grad(hash_int4(X + 1, Y + 1, Z, W), fx - 1.0, fy - 1.0, fz, fw),
+ noise_grad(hash_int4(X, Y, Z + 1, W), fx, fy, fz - 1.0, fw),
+ noise_grad(hash_int4(X + 1, Y, Z + 1, W), fx - 1.0, fy, fz - 1.0, fw),
+ noise_grad(hash_int4(X, Y + 1, Z + 1, W), fx, fy - 1.0, fz - 1.0, fw),
+ noise_grad(hash_int4(X + 1, Y + 1, Z + 1, W), fx - 1.0, fy - 1.0, fz - 1.0, fw),
+ u,
+ v,
+ t),
+ tri_mix(noise_grad(hash_int4(X, Y, Z, W + 1), fx, fy, fz, fw - 1.0),
+ noise_grad(hash_int4(X + 1, Y, Z, W + 1), fx - 1.0, fy, fz, fw - 1.0),
+ noise_grad(hash_int4(X, Y + 1, Z, W + 1), fx, fy - 1.0, fz, fw - 1.0),
+ noise_grad(hash_int4(X + 1, Y + 1, Z, W + 1), fx - 1.0, fy - 1.0, fz, fw - 1.0),
+ noise_grad(hash_int4(X, Y, Z + 1, W + 1), fx, fy, fz - 1.0, fw - 1.0),
+ noise_grad(hash_int4(X + 1, Y, Z + 1, W + 1), fx - 1.0, fy, fz - 1.0, fw - 1.0),
+ noise_grad(hash_int4(X, Y + 1, Z + 1, W + 1), fx, fy - 1.0, fz - 1.0, fw - 1.0),
+ noise_grad(hash_int4(X + 1, Y + 1, Z + 1, W + 1), fx - 1.0, fy - 1.0, fz - 1.0, fw - 1.0),
+ u,
+ v,
+ t),
+ s);
+
+ return r;
+}
+
+/* Remap the output of noise to a predictable range [-1, 1].
+ * The values were computed experimentally by the OSL developers.
+ */
+float noise_scale1(float result)
+{
+ return 0.2500 * result;
+}
- noise_u[1] = noise_nerp(u,
- noise_grad(hash(X, Y + 1, Z + 1), fx, fy - 1.0, fz - 1.0),
- noise_grad(hash(X + 1, Y + 1, Z + 1), fx - 1.0, fy - 1.0, fz - 1.0));
+float noise_scale2(float result)
+{
+ return 0.6616 * result;
+}
- noise_v[1] = noise_nerp(v, noise_u[0], noise_u[1]);
+float noise_scale3(float result)
+{
+ return 0.9820 * result;
+}
- float r = noise_scale3(noise_nerp(w, noise_v[0], noise_v[1]));
+float noise_scale4(float result)
+{
+ return 0.8344 * result;
+}
- return (isinf(r)) ? 0.0 : r;
+float snoise(float p)
+{
+ float r = noise_perlin(p);
+ return (isinf(r)) ? 0.0 : noise_scale1(r);
}
-float noise(vec3 p)
+float noise(float p)
{
- return 0.5 * noise_perlin(p.x, p.y, p.z) + 0.5;
+ return 0.5 * snoise(p) + 0.5;
+}
+
+float snoise(vec2 p)
+{
+ float r = noise_perlin(p);
+ return (isinf(r)) ? 0.0 : noise_scale2(r);
+}
+
+float noise(vec2 p)
+{
+ return 0.5 * snoise(p) + 0.5;
}
float snoise(vec3 p)
{
- return noise_perlin(p.x, p.y, p.z);
+ float r = noise_perlin(p);
+ return (isinf(r)) ? 0.0 : noise_scale3(r);
+}
+
+float noise(vec3 p)
+{
+ return 0.5 * snoise(p) + 0.5;
+}
+
+float snoise(vec4 p)
+{
+ float r = noise_perlin(p);
+ return (isinf(r)) ? 0.0 : noise_scale4(r);
}
-float noise_turbulence(vec3 p, float octaves, int hard)
+float noise(vec4 p)
+{
+ return 0.5 * snoise(p) + 0.5;
+}
+
+/* The following 4 functions are exactly the same but with different input type.
+ * When refactoring, simply copy the function body to the rest of the functions.
+ */
+float noise_turbulence(float p, float octaves)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ octaves = clamp(octaves, 0.0, 16.0);
+ int n = int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = 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;
+ }
+}
+
+float noise_turbulence(vec2 p, float octaves)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ octaves = clamp(octaves, 0.0, 16.0);
+ int n = int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = 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;
+ }
+}
+
+float noise_turbulence(vec3 p, float octaves)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ octaves = clamp(octaves, 0.0, 16.0);
+ int n = int(octaves);
+ for (int i = 0; i <= n; i++) {
+ float t = noise(fscale * p);
+ sum += t * amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+ float rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ float t = 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;
+ }
+}
+
+float noise_turbulence(vec4 p, float octaves)
{
float fscale = 1.0;
float amp = 1.0;
@@ -2888,9 +3495,6 @@ float noise_turbulence(vec3 p, float octaves, int hard)
int n = int(octaves);
for (int i = 0; i <= n; i++) {
float t = noise(fscale * p);
- if (hard != 0) {
- t = abs(2.0 * t - 1.0);
- }
sum += t * amp;
amp *= 0.5;
fscale *= 2.0;
@@ -2898,9 +3502,6 @@ float noise_turbulence(vec3 p, float octaves, int hard)
float rmd = octaves - floor(octaves);
if (rmd != 0.0) {
float t = noise(fscale * p);
- if (hard != 0) {
- t = abs(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));
@@ -2912,27 +3513,334 @@ float noise_turbulence(vec3 p, float octaves, int hard)
}
}
-void node_tex_noise(
- vec3 co, float scale, float detail, float distortion, out vec4 color, out float fac)
+/* 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 + hash_float_to_float(seed) * 100.0;
+}
+
+vec2 random_vec2_offset(float seed)
+{
+ return vec2(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0);
+}
+
+vec3 random_vec3_offset(float seed)
+{
+ return vec3(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 2.0)) * 100.0);
+}
+
+vec4 random_vec4_offset(float seed)
+{
+ return vec4(100.0 + hash_vec2_to_float(vec2(seed, 0.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 1.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 2.0)) * 100.0,
+ 100.0 + hash_vec2_to_float(vec2(seed, 3.0)) * 100.0);
+}
+
+void node_noise_texture_1d(
+ vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+{
+ float p = w * scale;
+ if (distortion != 0.0) {
+ p += noise(p + random_float_offset(0.0)) * distortion;
+ }
+
+ value = noise_turbulence(p, detail);
+ color = vec4(value,
+ noise_turbulence(p + random_float_offset(1.0), detail),
+ noise_turbulence(p + random_float_offset(2.0), detail),
+ 1.0);
+}
+
+void node_noise_texture_2d(
+ vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+{
+ vec2 p = co.xy * scale;
+ if (distortion != 0.0) {
+ p += vec2(noise(p + random_vec2_offset(0.0)) * distortion,
+ noise(p + random_vec2_offset(1.0)) * distortion);
+ }
+
+ value = noise_turbulence(p, detail);
+ color = vec4(value,
+ noise_turbulence(p + random_vec2_offset(2.0), detail),
+ noise_turbulence(p + random_vec2_offset(3.0), detail),
+ 1.0);
+}
+
+void node_noise_texture_3d(
+ vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
{
vec3 p = co * scale;
- int hard = 0;
if (distortion != 0.0) {
- vec3 r, offset = vec3(13.5, 13.5, 13.5);
- r.x = noise(p + offset) * distortion;
- r.y = noise(p) * distortion;
- r.z = noise(p - offset) * distortion;
- p += r;
+ p += vec3(noise(p + random_vec3_offset(0.0)) * distortion,
+ noise(p + random_vec3_offset(1.0)) * distortion,
+ noise(p + random_vec3_offset(2.0)) * distortion);
+ }
+
+ value = noise_turbulence(p, detail);
+ color = vec4(value,
+ noise_turbulence(p + random_vec3_offset(3.0), detail),
+ noise_turbulence(p + random_vec3_offset(4.0), detail),
+ 1.0);
+}
+
+void node_noise_texture_4d(
+ vec3 co, float w, float scale, float detail, float distortion, out float value, out vec4 color)
+{
+ vec4 p = vec4(co, w) * scale;
+ if (distortion != 0.0) {
+ p += vec4(noise(p + random_vec4_offset(0.0)) * distortion,
+ noise(p + random_vec4_offset(1.0)) * distortion,
+ noise(p + random_vec4_offset(2.0)) * distortion,
+ noise(p + random_vec4_offset(3.0)) * distortion);
+ }
+
+ value = noise_turbulence(p, detail);
+ color = vec4(value,
+ noise_turbulence(p + random_vec4_offset(4.0), detail),
+ noise_turbulence(p + random_vec4_offset(5.0), detail),
+ 1.0);
+}
+
+/* 1D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+void node_tex_musgrave_fBm_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float rmd;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * snoise(p) * pwr;
+ }
+
+ fac = value;
+}
+
+/* 1D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+void node_tex_musgrave_multi_fractal_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float rmd;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
+ }
+
+ fac = value;
+}
+
+/* 1D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hetero_terrain_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value, increment, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < int(octaves); i++) {
+ increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ fac = value;
+}
+
+/* 1D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hybrid_multi_fractal_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float result, signal, weight, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ result = snoise(p) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ result += rmd * ((snoise(p) + offset) * pwr);
+ }
+
+ fac = result;
+}
+
+/* 1D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_ridged_multi_fractal_1d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ float p = w * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float result, signal, weight;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ result = signal;
+ weight = 1.0;
+
+ for (int i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
}
- fac = noise_turbulence(p, detail, hard);
- color = vec4(fac,
- noise_turbulence(vec3(p.y, p.x, p.z), detail, hard),
- noise_turbulence(vec3(p.y, p.z, p.x), detail, hard),
- 1);
+ fac = result;
}
-/* Musgrave fBm
+/* 2D Musgrave fBm
*
* H: fractal increment parameter
* lacunarity: gap between successive frequencies
@@ -2941,8 +3849,248 @@ void node_tex_noise(
* from "Texturing and Modelling: A procedural approach"
*/
-float noise_musgrave_fBm(vec3 p, float H, float lacunarity, float octaves)
+void node_tex_musgrave_fBm_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float rmd;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * snoise(p) * pwr;
+ }
+
+ fac = value;
+}
+
+/* 2D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+void node_tex_musgrave_multi_fractal_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float rmd;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
+ }
+
+ fac = value;
+}
+
+/* 2D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hetero_terrain_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value, increment, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < int(octaves); i++) {
+ increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ fac = value;
+}
+
+/* 2D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hybrid_multi_fractal_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float result, signal, weight, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ result = snoise(p) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ result += rmd * ((snoise(p) + offset) * pwr);
+ }
+
+ fac = result;
+}
+
+/* 2D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_ridged_multi_fractal_2d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec2 p = co.xy * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float result, signal, weight;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ result = signal;
+ weight = 1.0;
+
+ for (int i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ fac = result;
+}
+
+/* 3D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+void node_tex_musgrave_fBm_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
float rmd;
float value = 0.0;
float pwr = 1.0;
@@ -2959,18 +4107,31 @@ float noise_musgrave_fBm(vec3 p, float H, float lacunarity, float octaves)
value += rmd * snoise(p) * pwr;
}
- return value;
+ fac = value;
}
-/* Musgrave Multifractal
+/* 3D Musgrave Multifractal
*
* H: highest fractal dimension
* lacunarity: gap between successive frequencies
* octaves: number of frequencies in the fBm
*/
-float noise_musgrave_multi_fractal(vec3 p, float H, float lacunarity, float octaves)
+void node_tex_musgrave_multi_fractal_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
float rmd;
float value = 1.0;
float pwr = 1.0;
@@ -2987,10 +4148,10 @@ float noise_musgrave_multi_fractal(vec3 p, float H, float lacunarity, float octa
value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
}
- return value;
+ fac = value;
}
-/* Musgrave Heterogeneous Terrain
+/* 3D Musgrave Heterogeneous Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -2998,8 +4159,21 @@ float noise_musgrave_multi_fractal(vec3 p, float H, float lacunarity, float octa
* offset: raises the terrain from `sea level'
*/
-float noise_musgrave_hetero_terrain(vec3 p, float H, float lacunarity, float octaves, float offset)
+void node_tex_musgrave_hetero_terrain_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
float value, increment, rmd;
float pwHL = pow(lacunarity, -H);
float pwr = pwHL;
@@ -3021,10 +4195,10 @@ float noise_musgrave_hetero_terrain(vec3 p, float H, float lacunarity, float oct
value += rmd * increment;
}
- return value;
+ fac = value;
}
-/* Hybrid Additive/Multiplicative Multifractal Terrain
+/* 3D Hybrid Additive/Multiplicative Multifractal Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -3032,9 +4206,21 @@ float noise_musgrave_hetero_terrain(vec3 p, float H, float lacunarity, float oct
* offset: raises the terrain from `sea level'
*/
-float noise_musgrave_hybrid_multi_fractal(
- vec3 p, float H, float lacunarity, float octaves, float offset, float gain)
+void node_tex_musgrave_hybrid_multi_fractal_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
float result, signal, weight, rmd;
float pwHL = pow(lacunarity, -H);
float pwr = pwHL;
@@ -3060,10 +4246,10 @@ float noise_musgrave_hybrid_multi_fractal(
result += rmd * ((snoise(p) + offset) * pwr);
}
- return result;
+ fac = result;
}
-/* Ridged Multifractal Terrain
+/* 3D Ridged Multifractal Terrain
*
* H: fractal dimension of the roughest area
* lacunarity: gap between successive frequencies
@@ -3071,9 +4257,21 @@ float noise_musgrave_hybrid_multi_fractal(
* offset: raises the terrain from `sea level'
*/
-float noise_musgrave_ridged_multi_fractal(
- vec3 p, float H, float lacunarity, float octaves, float offset, float gain)
+void node_tex_musgrave_ridged_multi_fractal_3d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
{
+ vec3 p = co * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
float result, signal, weight;
float pwHL = pow(lacunarity, -H);
float pwr = pwHL;
@@ -3093,52 +4291,234 @@ float noise_musgrave_ridged_multi_fractal(
pwr *= pwHL;
}
- return result;
+ fac = result;
}
-float svm_musgrave(int type,
- float dimension,
- float lacunarity,
- float octaves,
- float offset,
- float intensity,
- float gain,
- vec3 p)
-{
- if (type == 0 /* NODE_MUSGRAVE_MULTIFRACTAL */) {
- return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
+/* 4D Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+void node_tex_musgrave_fBm_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float rmd;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value += snoise(p) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
}
- else if (type == 1 /* NODE_MUSGRAVE_FBM */) {
- return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value += rmd * snoise(p) * pwr;
}
- else if (type == 2 /* NODE_MUSGRAVE_HYBRID_MULTIFRACTAL */) {
- return intensity *
- noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
+
+ fac = value;
+}
+
+/* 4D Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+void node_tex_musgrave_multi_fractal_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float rmd;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+
+ for (int i = 0; i < int(octaves); i++) {
+ value *= (pwr * snoise(p) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
}
- else if (type == 3 /* NODE_MUSGRAVE_RIDGED_MULTIFRACTAL */) {
- return intensity *
- noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ value *= (rmd * pwr * snoise(p) + 1.0); /* correct? */
}
- else if (type == 4 /* NODE_MUSGRAVE_HETERO_TERRAIN */) {
- return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
+
+ fac = value;
+}
+
+/* 4D Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hetero_terrain_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float value, increment, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + snoise(p);
+ p *= lacunarity;
+
+ for (int i = 1; i < int(octaves); i++) {
+ increment = (snoise(p) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
}
- return 0.0;
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ increment = (snoise(p) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ fac = value;
}
-void node_tex_musgrave(vec3 co,
- float scale,
- float detail,
- float dimension,
- float lacunarity,
- float offset,
- float gain,
- float type,
- out vec4 color,
- out float fac)
-{
- fac = svm_musgrave(int(type), dimension, lacunarity, detail, offset, 1.0, gain, co *scale);
+/* 4D Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_hybrid_multi_fractal_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float result, signal, weight, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ result = snoise(p) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+ if (weight > 1.0) {
+ weight = 1.0;
+ }
+
+ signal = (snoise(p) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if (rmd != 0.0) {
+ result += rmd * ((snoise(p) + offset) * pwr);
+ }
+
+ fac = result;
+}
+
+/* 4D Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+void node_tex_musgrave_ridged_multi_fractal_4d(vec3 co,
+ float w,
+ float scale,
+ float detail,
+ float dimension,
+ float lac,
+ float offset,
+ float gain,
+ out float fac)
+{
+ vec4 p = vec4(co, w) * scale;
+ float H = max(dimension, 1e-5);
+ float octaves = clamp(detail, 0.0, 16.0);
+ float lacunarity = max(lac, 1e-5);
+
+ float result, signal, weight;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ result = signal;
+ weight = 1.0;
+
+ for (int i = 1; i < int(octaves); i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - abs(snoise(p));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
- color = vec4(fac, fac, fac, 1.0);
+ fac = result;
}
void node_tex_sky(vec3 co, out vec4 color)
@@ -3146,121 +4526,1010 @@ void node_tex_sky(vec3 co, out vec4 color)
color = vec4(1.0);
}
-void node_tex_voronoi(vec3 co,
- float scale,
- float exponent,
- float coloring,
- float metric,
- float feature,
- out vec4 color,
- out float fac)
+/* **** Voronoi Texture **** */
+
+/* Each of the following functions computes a certain voronoi feature in a certain dimension.
+ * Independent functions are used because every feature/dimension have a different search area.
+ *
+ * This code is based on the following:
+ * Base code : http://www.iquilezles.org/www/articles/smoothvoronoi/smoothvoronoi.htm
+ * Smoothing : https://iquilezles.untergrund.net/www/articles/smin/smin.htm
+ * Distance To Edge Method : https://www.shadertoy.com/view/llG3zy
+ */
+
+/* **** 1D Voronoi **** */
+
+float voronoi_distance(float a, float b, float metric, float exponent)
+{
+ return distance(a, b);
+}
+
+void node_tex_voronoi_f1_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ float targetOffset, targetPosition;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_float_to_vec3(cellPosition + targetOffset);
+ outW = safe_divide(targetPosition + cellPosition, scale);
+}
+
+void node_tex_voronoi_smooth_f1_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+ smoothness = max(smoothness, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float smoothDistance = 0.0;
+ float smoothPosition = 0.0;
+ vec3 smoothColor = vec3(0.0);
+ for (int i = -2; i <= 2; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float weight = exp(-smoothness * distanceToPoint);
+ smoothDistance += weight;
+ smoothColor += hash_float_to_vec3(cellPosition + cellOffset) * weight;
+ smoothPosition += pointPosition * weight;
+ }
+ outDistance = -log(smoothDistance) / smoothness;
+ outColor.xyz = smoothColor / smoothDistance;
+ outW = safe_divide(cellPosition + smoothPosition / smoothDistance, scale);
+}
+
+void node_tex_voronoi_f2_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ float offsetF1 = 0.0;
+ float positionF1 = 0.0;
+ float offsetF2, positionF2;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_float_to_vec3(cellPosition + offsetF2);
+ outW = safe_divide(positionF2 + cellPosition, scale);
+}
+
+void node_tex_voronoi_distance_to_edge_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ minDistance = min(distanceToPoint, minDistance);
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_1d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ float scaledCoord = w * scale;
+ float cellPosition = floor(scaledCoord);
+ float localPosition = scaledCoord - cellPosition;
+
+ float closestPoint;
+ float closestPointOffset;
+ float minDistance = 8.0;
+ for (int i = -1; i <= 1; i++) {
+ float cellOffset = float(i);
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+
+ minDistance = 8.0;
+ float closestPointToClosestPoint;
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0)
+ continue;
+ float cellOffset = float(i) + closestPointOffset;
+ float pointPosition = cellOffset + hash_float_to_float(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 2D Voronoi **** */
+
+float voronoi_distance(vec2 a, vec2 b, float metric, float exponent)
{
- vec3 p = co * scale;
- int xx, yy, zz, xi, yi, zi;
- vec4 da = vec4(1e10);
- vec3 pa[4] = vec3[4](vec3(0.0), vec3(0.0), vec3(0.0), vec3(0.0));
-
- xi = floor_to_int(p[0]);
- yi = floor_to_int(p[1]);
- zi = floor_to_int(p[2]);
-
- for (xx = xi - 1; xx <= xi + 1; xx++) {
- for (yy = yi - 1; yy <= yi + 1; yy++) {
- for (zz = zi - 1; zz <= zi + 1; zz++) {
- vec3 ip = vec3(xx, yy, zz);
- vec3 vp = cellnoise_color(ip);
- vec3 pd = p - (vp + ip);
-
- float d = 0.0;
- if (metric == 0.0) { /* SHD_VORONOI_DISTANCE 0 */
- d = dot(pd, pd);
- }
- else if (metric == 1.0) { /* SHD_VORONOI_MANHATTAN 1 */
- d = abs(pd[0]) + abs(pd[1]) + abs(pd[2]);
- }
- else if (metric == 2.0) { /* SHD_VORONOI_CHEBYCHEV 2 */
- d = max(abs(pd[0]), max(abs(pd[1]), abs(pd[2])));
- }
- else if (metric == 3.0) { /* SHD_VORONOI_MINKOWSKI 3 */
- d = pow(pow(abs(pd[0]), exponent) + pow(abs(pd[1]), exponent) +
- pow(abs(pd[2]), exponent),
- 1.0 / exponent);
- }
+ if (metric == 0.0) // SHD_VORONOI_EUCLIDEAN
+ return distance(a, b);
+ else if (metric == 1.0) // SHD_VORONOI_MANHATTAN
+ return abs(a.x - b.x) + abs(a.y - b.y);
+ else if (metric == 2.0) // SHD_VORONOI_CHEBYCHEV
+ return max(abs(a.x - b.x), abs(a.y - b.y));
+ else if (metric == 3.0) // SHD_VORONOI_MINKOWSKI
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent), 1.0 / exponent);
+ else
+ return 0.0;
+}
- vp += vec3(xx, yy, zz);
- if (d < da[0]) {
- da.yzw = da.xyz;
- da[0] = d;
+void node_tex_voronoi_f1_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ vec2 targetOffset, targetPosition;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_vec2_to_vec3(cellPosition + targetOffset);
+ outPosition = vec3(safe_divide(targetPosition + cellPosition, scale), 0.0);
+}
+
+void node_tex_voronoi_smooth_f1_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+ smoothness = max(smoothness, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ vec3 smoothColor = vec3(0.0);
+ float smoothDistance = 0.0;
+ vec2 smoothPosition = vec2(0.0);
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float weight = exp(-smoothness * distanceToPoint);
+ smoothDistance += weight;
+ smoothColor += hash_vec2_to_vec3(cellPosition + cellOffset) * weight;
+ smoothPosition += pointPosition * weight;
+ }
+ }
+ outDistance = -log(smoothDistance) / smoothness;
+ outColor.xyz = smoothColor / smoothDistance;
+ outPosition = vec3(safe_divide(cellPosition + smoothPosition / smoothDistance, scale), 0.0);
+}
+
+void node_tex_voronoi_f2_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vec2 offsetF1 = vec2(0.0);
+ vec2 positionF1 = vec2(0.0);
+ vec2 offsetF2, positionF2;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_vec2_to_vec3(cellPosition + offsetF2);
+ outPosition = vec3(safe_divide(positionF2 + cellPosition, scale), 0.0);
+}
+
+void node_tex_voronoi_distance_to_edge_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ vec2 vectorToClosest;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 vectorToPoint = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * jitter -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = pa[0];
- pa[0] = vp;
- }
- else if (d < da[1]) {
- da.zw = da.yz;
- da[1] = d;
+ minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 vectorToPoint = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * jitter -
+ localPosition;
+ vec2 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_2d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ vec2 scaledCoord = coord.xy * scale;
+ vec2 cellPosition = floor(scaledCoord);
+ vec2 localPosition = scaledCoord - cellPosition;
+
+ vec2 closestPoint;
+ vec2 closestPointOffset;
+ float minDistance = 8.0;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec2 cellOffset = vec2(i, j);
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
- pa[3] = pa[2];
- pa[2] = pa[1];
- pa[1] = vp;
- }
- else if (d < da[2]) {
- da[3] = da[2];
- da[2] = d;
+ minDistance = 8.0;
+ vec2 closestPointToClosestPoint;
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0)
+ continue;
+ vec2 cellOffset = vec2(i, j) + closestPointOffset;
+ vec2 pointPosition = cellOffset + hash_vec2_to_vec2(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 3D Voronoi **** */
- pa[3] = pa[2];
- pa[2] = vp;
+float voronoi_distance(vec3 a, vec3 b, float metric, float exponent)
+{
+ if (metric == 0.0) // SHD_VORONOI_EUCLIDEAN
+ return distance(a, b);
+ else if (metric == 1.0) // SHD_VORONOI_MANHATTAN
+ return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z);
+ else if (metric == 2.0) // SHD_VORONOI_CHEBYCHEV
+ return max(abs(a.x - b.x), max(abs(a.y - b.y), abs(a.z - b.z)));
+ else if (metric == 3.0) // SHD_VORONOI_MINKOWSKI
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent) +
+ pow(abs(a.z - b.z), exponent),
+ 1.0 / exponent);
+ else
+ return 0.0;
+}
+
+void node_tex_voronoi_f1_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ vec3 targetOffset, targetPosition;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset + hash_vec3_to_vec3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
+ }
+ outDistance = minDistance;
+ outColor.xyz = hash_vec3_to_vec3(cellPosition + targetOffset);
+ outPosition = safe_divide(targetPosition + cellPosition, scale);
+}
+
+void node_tex_voronoi_smooth_f1_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+ smoothness = max(smoothness, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ vec3 smoothColor = vec3(0.0);
+ float smoothDistance = 0.0;
+ vec3 smoothPosition = vec3(0.0);
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset + hash_vec3_to_vec3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float weight = exp(-smoothness * distanceToPoint);
+ smoothDistance += weight;
+ smoothColor += hash_vec3_to_vec3(cellPosition + cellOffset) * weight;
+ smoothPosition += pointPosition * weight;
+ }
+ }
+ }
+ outDistance = -log(smoothDistance) / smoothness;
+ outColor.xyz = smoothColor / smoothDistance;
+ outPosition = safe_divide(cellPosition + smoothPosition / smoothDistance, scale);
+}
+
+void node_tex_voronoi_f2_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vec3 offsetF1 = vec3(0.0);
+ vec3 positionF1 = vec3(0.0);
+ vec3 offsetF2, positionF2;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset + hash_vec3_to_vec3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
}
- else if (d < da[3]) {
- da[3] = d;
- pa[3] = vp;
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
}
}
}
}
-
- if (coloring == 0.0) {
- /* Intensity output */
- if (feature == 0.0) { /* F1 */
- fac = abs(da[0]);
+ outDistance = distanceF2;
+ outColor.xyz = hash_vec3_to_vec3(cellPosition + offsetF2);
+ outPosition = safe_divide(positionF2 + cellPosition, scale);
+}
+
+void node_tex_voronoi_distance_to_edge_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ vec3 vectorToClosest;
+ float minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 vectorToPoint = cellOffset + hash_vec3_to_vec3(cellPosition + cellOffset) * jitter -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
}
- else if (feature == 1.0) { /* F2 */
- fac = abs(da[1]);
+ }
+
+ minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 vectorToPoint = cellOffset + hash_vec3_to_vec3(cellPosition + cellOffset) * jitter -
+ localPosition;
+ vec3 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
}
- else if (feature == 2.0) { /* F3 */
- fac = abs(da[2]);
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_3d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ vec3 scaledCoord = coord * scale;
+ vec3 cellPosition = floor(scaledCoord);
+ vec3 localPosition = scaledCoord - cellPosition;
+
+ vec3 closestPoint;
+ vec3 closestPointOffset;
+ float minDistance = 8.0;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec3 cellOffset = vec3(i, j, k);
+ vec3 pointPosition = cellOffset + hash_vec3_to_vec3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
}
- else if (feature == 3.0) { /* F4 */
- fac = abs(da[3]);
+ }
+
+ minDistance = 8.0;
+ vec3 closestPointToClosestPoint;
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0)
+ continue;
+ vec3 cellOffset = vec3(i, j, k) + closestPointOffset;
+ vec3 pointPosition = cellOffset + hash_vec3_to_vec3(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
}
- else if (feature == 4.0) { /* F2F1 */
- fac = abs(da[1] - da[0]);
+ }
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
+}
+
+/* **** 4D Voronoi **** */
+
+float voronoi_distance(vec4 a, vec4 b, float metric, float exponent)
+{
+ if (metric == 0.0) // SHD_VORONOI_EUCLIDEAN
+ return distance(a, b);
+ else if (metric == 1.0) // SHD_VORONOI_MANHATTAN
+ return abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z) + abs(a.w - b.w);
+ else if (metric == 2.0) // SHD_VORONOI_CHEBYCHEV
+ return max(abs(a.x - b.x), max(abs(a.y - b.y), max(abs(a.z - b.z), abs(a.w - b.w))));
+ else if (metric == 3.0) // SHD_VORONOI_MINKOWSKI
+ return pow(pow(abs(a.x - b.x), exponent) + pow(abs(a.y - b.y), exponent) +
+ pow(abs(a.z - b.z), exponent) + pow(abs(a.w - b.w), exponent),
+ 1.0 / exponent);
+ else
+ return 0.0;
+}
+
+void node_tex_voronoi_f1_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ float minDistance = 8.0;
+ vec4 targetOffset, targetPosition;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset + hash_vec4_to_vec4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < minDistance) {
+ targetOffset = cellOffset;
+ minDistance = distanceToPoint;
+ targetPosition = pointPosition;
+ }
+ }
+ }
}
- color = vec4(fac, fac, fac, 1.0);
}
- else {
- /* Color output */
- vec3 col = vec3(fac, fac, fac);
- if (feature == 0.0) { /* F1 */
- col = pa[0];
+ outDistance = minDistance;
+ outColor.xyz = hash_vec4_to_vec3(cellPosition + targetOffset);
+ vec4 p = safe_divide(targetPosition + cellPosition, scale);
+ outPosition = p.xyz;
+ outW = p.w;
+}
+
+void node_tex_voronoi_smooth_f1_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+ smoothness = max(smoothness, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ vec3 smoothColor = vec3(0.0);
+ float smoothDistance = 0.0;
+ vec4 smoothPosition = vec4(0.0);
+ for (int u = -2; u <= 2; u++) {
+ for (int k = -2; k <= 2; k++) {
+ for (int j = -2; j <= 2; j++) {
+ for (int i = -2; i <= 2; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset + hash_vec4_to_vec4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ float weight = exp(-smoothness * distanceToPoint);
+ smoothDistance += weight;
+ smoothColor += hash_vec4_to_vec3(cellPosition + cellOffset) * weight;
+ smoothPosition += pointPosition * weight;
+ }
+ }
}
- else if (feature == 1.0) { /* F2 */
- col = pa[1];
+ }
+ outDistance = -log(smoothDistance) / smoothness;
+ outColor.xyz = smoothColor / smoothDistance;
+ vec4 p = safe_divide(cellPosition + smoothPosition / smoothDistance, scale);
+ outPosition = p.xyz;
+ outW = p.w;
+}
+
+void node_tex_voronoi_f2_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ float distanceF1 = 8.0;
+ float distanceF2 = 8.0;
+ vec4 offsetF1 = vec4(0.0);
+ vec4 positionF1 = vec4(0.0);
+ vec4 offsetF2, positionF2;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset + hash_vec4_to_vec4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = voronoi_distance(pointPosition, localPosition, metric, exponent);
+ if (distanceToPoint < distanceF1) {
+ distanceF2 = distanceF1;
+ distanceF1 = distanceToPoint;
+ offsetF2 = offsetF1;
+ offsetF1 = cellOffset;
+ positionF2 = positionF1;
+ positionF1 = pointPosition;
+ }
+ else if (distanceToPoint < distanceF2) {
+ distanceF2 = distanceToPoint;
+ offsetF2 = cellOffset;
+ positionF2 = pointPosition;
+ }
+ }
+ }
}
- else if (feature == 2.0) { /* F3 */
- col = pa[2];
+ }
+ outDistance = distanceF2;
+ outColor.xyz = hash_vec4_to_vec3(cellPosition + offsetF2);
+ vec4 p = safe_divide(positionF2 + cellPosition, scale);
+ outPosition = p.xyz;
+ outW = p.w;
+}
+
+void node_tex_voronoi_distance_to_edge_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ vec4 vectorToClosest;
+ float minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 vectorToPoint = cellOffset + hash_vec4_to_vec4(cellPosition + cellOffset) * jitter -
+ localPosition;
+ float distanceToPoint = dot(vectorToPoint, vectorToPoint);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ vectorToClosest = vectorToPoint;
+ }
+ }
+ }
}
- else if (feature == 3.0) { /* F4 */
- col = pa[3];
+ }
+
+ minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 vectorToPoint = cellOffset + hash_vec4_to_vec4(cellPosition + cellOffset) * jitter -
+ localPosition;
+ vec4 perpendicularToEdge = vectorToPoint - vectorToClosest;
+ if (dot(perpendicularToEdge, perpendicularToEdge) > 0.0001) {
+ float distanceToEdge = dot((vectorToClosest + vectorToPoint) / 2.0,
+ normalize(perpendicularToEdge));
+ minDistance = min(minDistance, distanceToEdge);
+ }
+ }
+ }
}
- else if (feature == 4.0) { /* F2F1 */
- col = abs(pa[1] - pa[0]);
+ }
+ outDistance = minDistance;
+}
+
+void node_tex_voronoi_n_sphere_radius_4d(vec3 coord,
+ float w,
+ float scale,
+ float smoothness,
+ float exponent,
+ float jitter,
+ float metric,
+ out float outDistance,
+ out vec4 outColor,
+ out vec3 outPosition,
+ out float outW,
+ out float outRadius)
+{
+ jitter = clamp(jitter, 0.0, 1.0);
+
+ vec4 scaledCoord = vec4(coord, w) * scale;
+ vec4 cellPosition = floor(scaledCoord);
+ vec4 localPosition = scaledCoord - cellPosition;
+
+ vec4 closestPoint;
+ vec4 closestPointOffset;
+ float minDistance = 8.0;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ vec4 cellOffset = vec4(i, j, k, u);
+ vec4 pointPosition = cellOffset + hash_vec4_to_vec4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(pointPosition, localPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPoint = pointPosition;
+ closestPointOffset = cellOffset;
+ }
+ }
+ }
}
+ }
- color = vec4(cellnoise_color(col), 1.0);
- fac = (color.x + color.y + color.z) * (1.0 / 3.0);
+ minDistance = 8.0;
+ vec4 closestPointToClosestPoint;
+ for (int u = -1; u <= 1; u++) {
+ for (int k = -1; k <= 1; k++) {
+ for (int j = -1; j <= 1; j++) {
+ for (int i = -1; i <= 1; i++) {
+ if (i == 0 && j == 0 && k == 0 && u == 0)
+ continue;
+ vec4 cellOffset = vec4(i, j, k, u) + closestPointOffset;
+ vec4 pointPosition = cellOffset + hash_vec4_to_vec4(cellPosition + cellOffset) * jitter;
+ float distanceToPoint = distance(closestPoint, pointPosition);
+ if (distanceToPoint < minDistance) {
+ minDistance = distanceToPoint;
+ closestPointToClosestPoint = pointPosition;
+ }
+ }
+ }
+ }
}
+ outRadius = distance(closestPointToClosestPoint, closestPoint) / 2.0;
}
float calc_wave(
@@ -3276,7 +5545,7 @@ float calc_wave(
}
if (distortion != 0.0) {
- n += distortion * noise_turbulence(p * detail_scale, detail, 0);
+ n += distortion * noise_turbulence(p * detail_scale, detail);
}
if (wave_profile == 0) { /* profile sin */
@@ -3349,14 +5618,17 @@ void node_light_falloff(
}
void node_object_info(mat4 obmat,
+ vec4 obcolor,
vec4 info,
float mat_index,
out vec3 location,
+ out vec4 color,
out float object_index,
out float material_index,
out float random)
{
location = obmat[3].xyz;
+ color = obcolor;
object_index = info.x;
material_index = mat_index;
random = info.z;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 75c0721f72a..f187ecd0764 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -184,6 +184,7 @@ typedef enum eNodeSocketFlag {
/** socket hidden automatically, to distinguish from manually hidden */
SOCK_AUTO_HIDDEN__DEPRECATED = (1 << 8),
SOCK_NO_INTERNAL_LINK = (1 << 9),
+ SOCK_COMPACT = (1 << 10),
} eNodeSocketFlag;
/* limit data in bNode to what we want to see saved? */
@@ -864,20 +865,22 @@ typedef struct NodeTexGradient {
typedef struct NodeTexNoise {
NodeTexBase base;
+ int dimensions;
+ char _pad[4];
} NodeTexNoise;
typedef struct NodeTexVoronoi {
NodeTexBase base;
- int coloring;
- int distance;
+ int dimensions;
int feature;
+ int distance;
char _pad[4];
} NodeTexVoronoi;
typedef struct NodeTexMusgrave {
NodeTexBase base;
int musgrave_type;
- char _pad[4];
+ int dimensions;
} NodeTexMusgrave;
typedef struct NodeTexWave {
@@ -989,6 +992,10 @@ typedef struct NodeShaderUVMap {
char uv_map[64];
} NodeShaderUVMap;
+typedef struct NodeShaderVertexColor {
+ char layer_name[64];
+} NodeShaderVertexColor;
+
typedef struct NodeShaderTexIES {
int mode;
@@ -1086,19 +1093,20 @@ typedef struct NodeCryptomatte {
#define SHD_NOISE_HARD 1
/* voronoi texture */
-#define SHD_VORONOI_DISTANCE 0
-#define SHD_VORONOI_MANHATTAN 1
-#define SHD_VORONOI_CHEBYCHEV 2
-#define SHD_VORONOI_MINKOWSKI 3
-
-#define SHD_VORONOI_INTENSITY 0
-#define SHD_VORONOI_CELLS 1
+enum {
+ SHD_VORONOI_EUCLIDEAN = 0,
+ SHD_VORONOI_MANHATTAN = 1,
+ SHD_VORONOI_CHEBYCHEV = 2,
+ SHD_VORONOI_MINKOWSKI = 3,
+};
-#define SHD_VORONOI_F1 0
-#define SHD_VORONOI_F2 1
-#define SHD_VORONOI_F3 2
-#define SHD_VORONOI_F4 3
-#define SHD_VORONOI_F2F1 4
+enum {
+ SHD_VORONOI_F1 = 0,
+ SHD_VORONOI_SMOOTH_F1 = 1,
+ SHD_VORONOI_F2 = 2,
+ SHD_VORONOI_DISTANCE_TO_EDGE = 3,
+ SHD_VORONOI_N_SPHERE_RADIUS = 4,
+};
/* musgrave texture */
#define SHD_MUSGRAVE_MULTIFRACTAL 0
@@ -1157,37 +1165,72 @@ typedef struct NodeCryptomatte {
#define SHD_AO_INSIDE 1
#define SHD_AO_LOCAL 2
+/* Mapping node vector types */
+enum {
+ NODE_MAPPING_TYPE_POINT = 0,
+ NODE_MAPPING_TYPE_TEXTURE = 1,
+ NODE_MAPPING_TYPE_VECTOR = 2,
+ NODE_MAPPING_TYPE_NORMAL = 3,
+};
+
/* math node clamp */
#define SHD_MATH_CLAMP 1
/* Math node operation/ */
enum {
NODE_MATH_ADD = 0,
- NODE_MATH_SUB = 1,
- NODE_MATH_MUL = 2,
+ NODE_MATH_SUBTRACT = 1,
+ NODE_MATH_MULTIPLY = 2,
NODE_MATH_DIVIDE = 3,
- NODE_MATH_SIN = 4,
- NODE_MATH_COS = 5,
- NODE_MATH_TAN = 6,
- NODE_MATH_ASIN = 7,
- NODE_MATH_ACOS = 8,
- NODE_MATH_ATAN = 9,
- NODE_MATH_POW = 10,
- NODE_MATH_LOG = 11,
- NODE_MATH_MIN = 12,
- NODE_MATH_MAX = 13,
+ NODE_MATH_SINE = 4,
+ NODE_MATH_COSINE = 5,
+ NODE_MATH_TANGENT = 6,
+ NODE_MATH_ARCSINE = 7,
+ NODE_MATH_ARCCOSINE = 8,
+ NODE_MATH_ARCTANGENT = 9,
+ NODE_MATH_POWER = 10,
+ NODE_MATH_LOGARITHM = 11,
+ NODE_MATH_MINIMUM = 12,
+ NODE_MATH_MAXIMUM = 13,
NODE_MATH_ROUND = 14,
- NODE_MATH_LESS = 15,
- NODE_MATH_GREATER = 16,
- NODE_MATH_MOD = 17,
- NODE_MATH_ABS = 18,
- NODE_MATH_ATAN2 = 19,
+ NODE_MATH_LESS_THAN = 15,
+ NODE_MATH_GREATER_THAN = 16,
+ NODE_MATH_MODULO = 17,
+ NODE_MATH_ABSOLUTE = 18,
+ NODE_MATH_ARCTAN2 = 19,
NODE_MATH_FLOOR = 20,
NODE_MATH_CEIL = 21,
- NODE_MATH_FRACT = 22,
+ NODE_MATH_FRACTION = 22,
NODE_MATH_SQRT = 23,
};
+/* Vector math node operation/ */
+enum {
+ NODE_VECTOR_MATH_ADD = 0,
+ NODE_VECTOR_MATH_SUBTRACT = 1,
+ NODE_VECTOR_MATH_MULTIPLY = 2,
+ NODE_VECTOR_MATH_DIVIDE = 3,
+
+ NODE_VECTOR_MATH_CROSS_PRODUCT = 4,
+ NODE_VECTOR_MATH_PROJECT = 5,
+ NODE_VECTOR_MATH_REFLECT = 6,
+ NODE_VECTOR_MATH_DOT_PRODUCT = 7,
+
+ NODE_VECTOR_MATH_DISTANCE = 8,
+ NODE_VECTOR_MATH_LENGTH = 9,
+ NODE_VECTOR_MATH_SCALE = 10,
+ NODE_VECTOR_MATH_NORMALIZE = 11,
+
+ NODE_VECTOR_MATH_SNAP = 12,
+ NODE_VECTOR_MATH_FLOOR = 13,
+ NODE_VECTOR_MATH_CEIL = 14,
+ NODE_VECTOR_MATH_MODULO = 15,
+ NODE_VECTOR_MATH_FRACTION = 16,
+ NODE_VECTOR_MATH_ABSOLUTE = 17,
+ NODE_VECTOR_MATH_MINIMUM = 18,
+ NODE_VECTOR_MATH_MAXIMUM = 19,
+};
+
/* mix rgb node flags */
#define SHD_MIXRGB_USE_ALPHA 1
#define SHD_MIXRGB_CLAMP 2
diff --git a/source/blender/makesrna/RNA_enum_types.h b/source/blender/makesrna/RNA_enum_types.h
index 02aaef44a1f..d8b3b379a71 100644
--- a/source/blender/makesrna/RNA_enum_types.h
+++ b/source/blender/makesrna/RNA_enum_types.h
@@ -183,6 +183,7 @@ extern const EnumPropertyItem rna_enum_file_sort_items[];
extern const EnumPropertyItem rna_enum_node_socket_in_out_items[];
extern const EnumPropertyItem rna_enum_node_math_items[];
+extern const EnumPropertyItem rna_enum_mapping_type_items[];
extern const EnumPropertyItem rna_enum_node_vec_math_items[];
extern const EnumPropertyItem rna_enum_node_filter_items[];
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index b28403bf28c..ba238402450 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -99,45 +99,94 @@ static const EnumPropertyItem node_chunksize_items[] = {
};
#endif
+const EnumPropertyItem rna_enum_mapping_type_items[] = {
+ {NODE_MAPPING_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
+ {NODE_MAPPING_TYPE_TEXTURE,
+ "TEXTURE",
+ 0,
+ "Texture",
+ "Transform a texture by inverse mapping the texture coordinate"},
+ {NODE_MAPPING_TYPE_VECTOR,
+ "VECTOR",
+ 0,
+ "Vector",
+ "Transform a direction vector. Location is ignored"},
+ {NODE_MAPPING_TYPE_NORMAL,
+ "NORMAL",
+ 0,
+ "Normal",
+ "Transform a unit normal vector. Location is ignored"},
+ {0, NULL, 0, NULL, NULL},
+};
+
const EnumPropertyItem rna_enum_node_math_items[] = {
- {NODE_MATH_ADD, "ADD", 0, "Add", ""},
- {NODE_MATH_SUB, "SUBTRACT", 0, "Subtract", ""},
- {NODE_MATH_MUL, "MULTIPLY", 0, "Multiply", ""},
- {NODE_MATH_DIVIDE, "DIVIDE", 0, "Divide", ""},
+ {NODE_MATH_ADD, "ADD", 0, "Add", "A + B"},
+ {NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"},
+ {NODE_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "A * B"},
+ {NODE_MATH_DIVIDE, "DIVIDE", 0, "Divide", "A / B"},
{0, "", ICON_NONE, NULL, NULL},
- {NODE_MATH_POW, "POWER", 0, "Power", ""},
- {NODE_MATH_LOG, "LOGARITHM", 0, "Logarithm", ""},
- {NODE_MATH_SQRT, "SQRT", 0, "Square Root", ""},
- {NODE_MATH_ABS, "ABSOLUTE", 0, "Absolute", ""},
+ {NODE_MATH_POWER, "POWER", 0, "Power", "A ^ B"},
+ {NODE_MATH_LOGARITHM, "LOGARITHM", 0, "Logarithm", "log(A) base B"},
+ {NODE_MATH_SQRT, "SQRT", 0, "Square Root", "sqrt(A)"},
+ {NODE_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "abs(A)"},
{0, "", ICON_NONE, NULL, NULL},
- {NODE_MATH_MIN, "MINIMUM", 0, "Minimum", ""},
- {NODE_MATH_MAX, "MAXIMUM", 0, "Maximum", ""},
- {NODE_MATH_LESS, "LESS_THAN", 0, "Less Than", ""},
- {NODE_MATH_GREATER, "GREATER_THAN", 0, "Greater Than", ""},
+ {NODE_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "min(A, B)"},
+ {NODE_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "max(A, B)"},
+ {NODE_MATH_LESS_THAN, "LESS_THAN", 0, "Less Than", "1 if A < B else 0"},
+ {NODE_MATH_GREATER_THAN, "GREATER_THAN", 0, "Greater Than", "1 if A > B else 0"},
{0, "", ICON_NONE, NULL, NULL},
- {NODE_MATH_ROUND, "ROUND", 0, "Round", ""},
- {NODE_MATH_FLOOR, "FLOOR", 0, "Floor", ""},
- {NODE_MATH_CEIL, "CEIL", 0, "Ceil", ""},
- {NODE_MATH_FRACT, "FRACT", 0, "Fract", ""},
- {NODE_MATH_MOD, "MODULO", 0, "Modulo", ""},
+ {NODE_MATH_ROUND,
+ "ROUND",
+ 0,
+ "Round",
+ "Round A to the nearest integer. Round upward if the fraction part is 0.5"},
+ {NODE_MATH_FLOOR, "FLOOR", 0, "Floor", "floor(A)"},
+ {NODE_MATH_CEIL, "CEIL", 0, "Ceil", "ceil(A)"},
+ {NODE_MATH_FRACTION, "FRACT", 0, "Fraction", "The fraction part of A"},
+ {NODE_MATH_MODULO, "MODULO", 0, "Modulo", "A mod B"},
{0, "", ICON_NONE, NULL, NULL},
- {NODE_MATH_SIN, "SINE", 0, "Sine", ""},
- {NODE_MATH_COS, "COSINE", 0, "Cosine", ""},
- {NODE_MATH_TAN, "TANGENT", 0, "Tangent", ""},
- {NODE_MATH_ASIN, "ARCSINE", 0, "Arcsine", ""},
- {NODE_MATH_ACOS, "ARCCOSINE", 0, "Arccosine", ""},
- {NODE_MATH_ATAN, "ARCTANGENT", 0, "Arctangent", ""},
- {NODE_MATH_ATAN2, "ARCTAN2", 0, "Arctan2", ""},
+ {NODE_MATH_SINE, "SINE", 0, "Sine", "sin(A)"},
+ {NODE_MATH_COSINE, "COSINE", 0, "Cosine", "cos(A)"},
+ {NODE_MATH_TANGENT, "TANGENT", 0, "Tangent", "tan(A)"},
+ {NODE_MATH_ARCSINE, "ARCSINE", 0, "Arcsine", "arcsin(A)"},
+ {NODE_MATH_ARCCOSINE, "ARCCOSINE", 0, "Arccosine", "arccos(A)"},
+ {NODE_MATH_ARCTANGENT, "ARCTANGENT", 0, "Arctangent", "arctan(A)"},
+ {NODE_MATH_ARCTAN2, "ARCTAN2", 0, "Arctan2", "arctan2(A, B)"},
{0, NULL, 0, NULL, NULL},
};
const EnumPropertyItem rna_enum_node_vec_math_items[] = {
- {0, "ADD", 0, "Add", ""},
- {1, "SUBTRACT", 0, "Subtract", ""},
- {2, "AVERAGE", 0, "Average", ""},
- {3, "DOT_PRODUCT", 0, "Dot Product", ""},
- {4, "CROSS_PRODUCT", 0, "Cross Product", ""},
- {5, "NORMALIZE", 0, "Normalize", ""},
+ {NODE_VECTOR_MATH_ADD, "ADD", 0, "Add", "A + B"},
+ {NODE_VECTOR_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"},
+ {NODE_VECTOR_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "Entrywise multiply."},
+ {NODE_VECTOR_MATH_DIVIDE, "DIVIDE", 0, "Divide", "Entrywise divide"},
+ {0, "", ICON_NONE, NULL, NULL},
+ {NODE_VECTOR_MATH_CROSS_PRODUCT, "CROSS_PRODUCT", 0, "Cross Product", "A x B"},
+ {NODE_VECTOR_MATH_PROJECT, "PROJECT", 0, "Project", "Project A onto B"},
+ {NODE_VECTOR_MATH_REFLECT, "REFLECT", 0, "Reflect", "Reflect A around the normal B"},
+ {NODE_VECTOR_MATH_DOT_PRODUCT, "DOT_PRODUCT", 0, "Dot Product", "A . B"},
+ {0, "", ICON_NONE, NULL, NULL},
+ {NODE_VECTOR_MATH_DISTANCE, "DISTANCE", 0, "Distance", "Distance between A and B"},
+ {NODE_VECTOR_MATH_LENGTH, "LENGTH", 0, "Length", "Length of A"},
+ {NODE_VECTOR_MATH_SCALE, "SCALE", 0, "Scale", "Multiply A by Scale"},
+ {NODE_VECTOR_MATH_NORMALIZE, "NORMALIZE", 0, "Normalize", "Normalize A"},
+ {0, "", ICON_NONE, NULL, NULL},
+ {NODE_VECTOR_MATH_SNAP, "SNAP", 0, "Snap", "Round A to the nearest integer multiple of B"},
+ {NODE_VECTOR_MATH_FLOOR, "FLOOR", 0, "Floor", "Entrywise floor"},
+ {NODE_VECTOR_MATH_CEIL, "CEIL", 0, "Ceil", "Entrywise ceil"},
+ {NODE_VECTOR_MATH_MODULO, "MODULO", 0, "Modulo", "Entrywise modulo"},
+ {NODE_VECTOR_MATH_FRACTION, "FRACTION", 0, "Fraction", "The fraction part of A entrywise"},
+ {NODE_VECTOR_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Entrywise absolute"},
+ {NODE_VECTOR_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "Entrywise minimum"},
+ {NODE_VECTOR_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "Entrywise maximum"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+const EnumPropertyItem rna_enum_node_tex_dimensions_items[] = {
+ {1, "1D", 0, "1D", ""},
+ {2, "2D", 0, "2D", ""},
+ {3, "3D", 0, "3D", ""},
+ {4, "4D", 0, "4D", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -3173,13 +3222,6 @@ static void rna_Image_Node_update_id(Main *UNUSED(bmain), Scene *UNUSED(scene),
nodeUpdate(ntree, node); /* to update image node sockets */
}
-static void rna_Mapping_Node_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- bNode *node = ptr->data;
- BKE_texture_mapping_init(node->storage);
- rna_Node_update(bmain, scene, ptr);
-}
-
static void rna_NodeOutputFile_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{
bNode *node = ptr->data;
@@ -3842,12 +3884,7 @@ static void def_math(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_math_items);
RNA_def_property_ui_text(prop, "Operation", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
-
- prop = RNA_def_property(srna, "use_clamp", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "custom2", SHD_MATH_CLAMP);
- RNA_def_property_ui_text(prop, "Clamp", "Clamp result of the node to 0..1 range");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_vector_math(StructRNA *srna)
@@ -3858,7 +3895,7 @@ static void def_vector_math(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, rna_enum_node_vec_math_items);
RNA_def_property_ui_text(prop, "Operation", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_rgb_curve(StructRNA *srna)
@@ -3982,68 +4019,13 @@ static void def_sh_output_linestyle(StructRNA *srna)
static void def_sh_mapping(StructRNA *srna)
{
- static const EnumPropertyItem prop_vect_type_items[] = {
- {TEXMAP_TYPE_TEXTURE,
- "TEXTURE",
- 0,
- "Texture",
- "Transform a texture by inverse mapping the texture coordinate"},
- {TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
- {TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"},
- {TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"},
- {0, NULL, 0, NULL, NULL},
- };
-
- static float default_1[3] = {1.f, 1.f, 1.f};
-
PropertyRNA *prop;
- RNA_def_struct_sdna_from(srna, "TexMapping", "storage");
-
prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_vect_type_items);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_mapping_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "translation", PROP_FLOAT, PROP_TRANSLATION);
- RNA_def_property_float_sdna(prop, NULL, "loc");
- RNA_def_property_ui_text(prop, "Location", "");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- /* Not PROP_XYZ, this is now in radians, no more degrees */
- prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
- RNA_def_property_float_sdna(prop, NULL, "rot");
- RNA_def_property_ui_text(prop, "Rotation", "");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "size");
- RNA_def_property_float_array_default(prop, default_1);
- RNA_def_property_flag(prop, PROP_PROPORTIONAL);
- RNA_def_property_ui_text(prop, "Scale", "");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "min", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "min");
- RNA_def_property_ui_text(prop, "Minimum", "Minimum value for clipping");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "max", PROP_FLOAT, PROP_XYZ);
- RNA_def_property_float_sdna(prop, NULL, "max");
- RNA_def_property_float_array_default(prop, default_1);
- RNA_def_property_ui_text(prop, "Maximum", "Maximum value for clipping");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "use_min", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MIN);
- RNA_def_property_ui_text(prop, "Has Minimum", "Whether to use minimum clipping value");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
-
- prop = RNA_def_property(srna, "use_max", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", TEXMAP_CLIP_MAX);
- RNA_def_property_ui_text(prop, "Has Maximum", "Whether to use maximum clipping value");
- RNA_def_property_update(prop, 0, "rna_Mapping_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
}
static void def_sh_attribute(StructRNA *srna)
@@ -4292,8 +4274,16 @@ static void def_sh_tex_gradient(StructRNA *srna)
static void def_sh_tex_noise(StructRNA *srna)
{
+ PropertyRNA *prop;
+
RNA_def_struct_sdna_from(srna, "NodeTexNoise", "storage");
def_sh_tex(srna);
+
+ prop = RNA_def_property(srna, "dimensions", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "dimensions");
+ RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
+ RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
static void def_sh_tex_checker(StructRNA *srna)
@@ -4368,34 +4358,54 @@ static void def_sh_tex_musgrave(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "NodeTexMusgrave", "storage");
def_sh_tex(srna);
+ prop = RNA_def_property(srna, "dimensions", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "dimensions");
+ RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
+ RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
+
prop = RNA_def_property(srna, "musgrave_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "musgrave_type");
RNA_def_property_enum_items(prop, prop_musgrave_type);
RNA_def_property_ui_text(prop, "Type", "");
- RNA_def_property_update(prop, 0, "rna_Node_update");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
static void def_sh_tex_voronoi(StructRNA *srna)
{
- static const EnumPropertyItem prop_coloring_items[] = {
- {SHD_VORONOI_INTENSITY, "INTENSITY", 0, "Intensity", "Only calculate intensity"},
- {SHD_VORONOI_CELLS, "CELLS", 0, "Cells", "Color cells by position"},
- {0, NULL, 0, NULL, NULL},
- };
-
static EnumPropertyItem prop_distance_items[] = {
- {SHD_VORONOI_DISTANCE, "DISTANCE", 0, "Distance", "Distance"},
- {SHD_VORONOI_MANHATTAN, "MANHATTAN", 0, "Manhattan", "Manhattan (city block) distance"},
+ {SHD_VORONOI_EUCLIDEAN, "EUCLIDEAN", 0, "Euclidean", "Euclidean distance"},
+ {SHD_VORONOI_MANHATTAN, "MANHATTAN", 0, "Manhattan", "Manhattan distance"},
{SHD_VORONOI_CHEBYCHEV, "CHEBYCHEV", 0, "Chebychev", "Chebychev distance"},
{SHD_VORONOI_MINKOWSKI, "MINKOWSKI", 0, "Minkowski", "Minkowski distance"},
{0, NULL, 0, NULL, NULL}};
static EnumPropertyItem prop_feature_items[] = {
- {SHD_VORONOI_F1, "F1", 0, "Closest", "Closest point"},
- {SHD_VORONOI_F2, "F2", 0, "2nd Closest", "2nd closest point"},
- {SHD_VORONOI_F3, "F3", 0, "3rd Closest", "3rd closest point"},
- {SHD_VORONOI_F4, "F4", 0, "4th Closest", "4th closest point"},
- {SHD_VORONOI_F2F1, "F2F1", 0, "Crackle", "Difference between 2nd and 1st closest point"},
+ {SHD_VORONOI_F1,
+ "F1",
+ 0,
+ "F1",
+ "Computes the distance to the closest point as well as its position and color"},
+ {SHD_VORONOI_SMOOTH_F1,
+ "SMOOTH_F1",
+ 0,
+ "Smooth F1",
+ "Smoothed version of F1. Weighted sum of neighbour voronoi cells"},
+ {SHD_VORONOI_F2,
+ "F2",
+ 0,
+ "F2",
+ "Computes the distance to the second closest point as well as its position and color"},
+ {SHD_VORONOI_DISTANCE_TO_EDGE,
+ "DISTANCE_TO_EDGE",
+ 0,
+ "Distance To Edge",
+ "Computes the distance to the edge of the vornoi cell"},
+ {SHD_VORONOI_N_SPHERE_RADIUS,
+ "N_SPHERE_RADIUS",
+ 0,
+ "N-Sphere Radius",
+ "Computes the radius of the n-sphere inscribed in the voronoi cell"},
{0, NULL, 0, NULL, NULL}};
PropertyRNA *prop;
@@ -4403,11 +4413,11 @@ static void def_sh_tex_voronoi(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "NodeTexVoronoi", "storage");
def_sh_tex(srna);
- prop = RNA_def_property(srna, "coloring", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "coloring");
- RNA_def_property_enum_items(prop, prop_coloring_items);
- RNA_def_property_ui_text(prop, "Coloring", "");
- RNA_def_property_update(prop, 0, "rna_Node_update");
+ prop = RNA_def_property(srna, "dimensions", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "dimensions");
+ RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
+ RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
prop = RNA_def_property(srna, "distance", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "distance");
@@ -4419,7 +4429,7 @@ static void def_sh_tex_voronoi(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "feature");
RNA_def_property_enum_items(prop, prop_feature_items);
RNA_def_property_ui_text(prop, "Feature Output", "");
- RNA_def_property_update(prop, 0, "rna_Node_update");
+ RNA_def_property_update(prop, 0, "rna_ShaderNode_socket_update");
}
static void def_sh_tex_wave(StructRNA *srna)
@@ -4454,6 +4464,17 @@ static void def_sh_tex_wave(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_Node_update");
}
+static void def_sh_tex_white_noise(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "dimensions", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, rna_enum_node_tex_dimensions_items);
+ RNA_def_property_ui_text(prop, "Dimensions", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
+}
+
static void def_sh_tex_coord(StructRNA *srna)
{
PropertyRNA *prop;
@@ -4812,6 +4833,19 @@ static void def_sh_uvmap(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "bNode", NULL);
}
+static void def_sh_vertex_color(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeShaderVertexColor", "storage");
+
+ prop = RNA_def_property(srna, "layer_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Vertex Color", "Vertex Color");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ RNA_def_struct_sdna_from(srna, "bNode", NULL);
+}
+
static void def_sh_uvalongstroke(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 6069e78d874..2fbe5634050 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -2808,7 +2808,7 @@ static void rna_def_object(BlenderRNA *brna)
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_ui_text(
prop, "Color", "Object color and alpha, used when faces have the ObColor mode enabled");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update_draw");
/* physics */
prop = RNA_def_property(srna, "field", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 28d2d722460..36e04c5829d 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -465,18 +465,6 @@ static void rna_def_texmapping(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL},
};
- static const EnumPropertyItem prop_vect_type_items[] = {
- {TEXMAP_TYPE_TEXTURE,
- "TEXTURE",
- 0,
- "Texture",
- "Transform a texture by inverse mapping the texture coordinate"},
- {TEXMAP_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
- {TEXMAP_TYPE_VECTOR, "VECTOR", 0, "Vector", "Transform a direction vector"},
- {TEXMAP_TYPE_NORMAL, "NORMAL", 0, "Normal", "Transform a normal vector with unit length"},
- {0, NULL, 0, NULL, NULL},
- };
-
static const EnumPropertyItem prop_xyz_mapping_items[] = {
{0, "NONE", 0, "None", ""},
{1, "X", 0, "X", ""},
@@ -493,7 +481,7 @@ static void rna_def_texmapping(BlenderRNA *brna)
prop = RNA_def_property(srna, "vector_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
- RNA_def_property_enum_items(prop, prop_vect_type_items);
+ RNA_def_property_enum_items(prop, rna_enum_mapping_type_items);
RNA_def_property_ui_text(prop, "Type", "Type of vector that the mapping transforms");
RNA_def_property_update(prop, 0, "rna_Texture_mapping_update");
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 80afcada4b9..e926772692b 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -197,16 +197,21 @@ set(SRC
shader/nodes/node_shader_tex_sky.c
shader/nodes/node_shader_tex_voronoi.c
shader/nodes/node_shader_tex_wave.c
+ shader/nodes/node_shader_tex_white_noise.c
shader/nodes/node_shader_uvAlongStroke.c
shader/nodes/node_shader_uvmap.c
+ shader/nodes/node_shader_vertex_color.c
shader/nodes/node_shader_valToRgb.c
shader/nodes/node_shader_value.c
+ shader/nodes/node_shader_map_range.c
+ shader/nodes/node_shader_clamp.c
shader/nodes/node_shader_vectMath.c
shader/nodes/node_shader_vectTransform.c
shader/nodes/node_shader_vector_displacement.c
shader/nodes/node_shader_volume_absorption.c
shader/nodes/node_shader_volume_principled.c
shader/nodes/node_shader_volume_scatter.c
+ shader/nodes/node_shader_volume_info.c
shader/nodes/node_shader_wavelength.c
shader/nodes/node_shader_wireframe.c
shader/node_shader_tree.c
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index ead42779bc0..d212772321b 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -48,6 +48,8 @@ void register_node_type_sh_brightcontrast(void);
void register_node_type_sh_mapping(void);
void register_node_type_sh_curve_vec(void);
void register_node_type_sh_curve_rgb(void);
+void register_node_type_sh_map_range(void);
+void register_node_type_sh_clamp(void);
void register_node_type_sh_math(void);
void register_node_type_sh_vect_math(void);
void register_node_type_sh_squeeze(void);
@@ -83,6 +85,8 @@ void register_node_type_sh_script(void);
void register_node_type_sh_normal_map(void);
void register_node_type_sh_tangent(void);
void register_node_type_sh_vect_transform(void);
+void register_node_type_sh_volume_info(void);
+void register_node_type_sh_vertex_color(void);
void register_node_type_sh_ambient_occlusion(void);
void register_node_type_sh_background(void);
@@ -129,6 +133,7 @@ void register_node_type_sh_tex_noise(void);
void register_node_type_sh_tex_checker(void);
void register_node_type_sh_bump(void);
void register_node_type_sh_tex_ies(void);
+void register_node_type_sh_tex_white_noise(void);
void register_node_type_sh_custom_group(bNodeType *ntype);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index f27c50ae736..75231624440 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -50,8 +50,10 @@ DefNode(ShaderNode, SH_NODE_MAPPING, def_sh_mapping, "MAPPIN
DefNode(ShaderNode, SH_NODE_CURVE_VEC, def_vector_curve, "CURVE_VEC", VectorCurve, "Vector Curves", "" )
DefNode(ShaderNode, SH_NODE_CURVE_RGB, def_rgb_curve, "CURVE_RGB", RGBCurve, "RGB Curves", "" )
DefNode(ShaderNode, SH_NODE_CAMERA, 0, "CAMERA", CameraData, "Camera Data", "" )
+DefNode(ShaderNode, SH_NODE_MAP_RANGE, 0, "MAP_RANGE", MapRange, "Map Range", "" )
+DefNode(ShaderNode, SH_NODE_CLAMP, 0, "CLAMP", Clamp, "Clamp", "" )
DefNode(ShaderNode, SH_NODE_MATH, def_math, "MATH", Math, "Math", "" )
-DefNode(ShaderNode, SH_NODE_VECT_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
+DefNode(ShaderNode, SH_NODE_VECTOR_MATH, def_vector_math, "VECT_MATH", VectorMath, "Vector Math", "" )
DefNode(ShaderNode, SH_NODE_SQUEEZE, 0, "SQUEEZE", Squeeze, "Squeeze Value", "" )
DefNode(ShaderNode, SH_NODE_INVERT, 0, "INVERT", Invert, "Invert", "" )
DefNode(ShaderNode, SH_NODE_SEPRGB, 0, "SEPRGB", SeparateRGB, "Separate RGB", "" )
@@ -92,6 +94,8 @@ DefNode(ShaderNode, SH_NODE_NEW_GEOMETRY, 0, "NEW
DefNode(ShaderNode, SH_NODE_LIGHT_PATH, 0, "LIGHT_PATH", LightPath, "Light Path", "" )
DefNode(ShaderNode, SH_NODE_LIGHT_FALLOFF, 0, "LIGHT_FALLOFF", LightFalloff, "Light Falloff", "" )
DefNode(ShaderNode, SH_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "" )
+DefNode(ShaderNode, SH_NODE_VOLUME_INFO, 0, "VOLUME_INFO", VolumeInfo, "Volume Info", "" )
+DefNode(ShaderNode, SH_NODE_VERTEX_COLOR, def_sh_vertex_color, "VERTEX_COLOR", VertexColor, "Vertex Color", "" )
DefNode(ShaderNode, SH_NODE_PARTICLE_INFO, 0, "PARTICLE_INFO", ParticleInfo, "Particle Info", "" )
DefNode(ShaderNode, SH_NODE_HAIR_INFO, 0, "HAIR_INFO", HairInfo, "Hair Info", "" )
DefNode(ShaderNode, SH_NODE_WIREFRAME, def_sh_tex_wireframe, "WIREFRAME", Wireframe, "Wireframe", "" )
@@ -125,6 +129,7 @@ DefNode(ShaderNode, SH_NODE_BEVEL, def_sh_bevel, "BEV
DefNode(ShaderNode, SH_NODE_DISPLACEMENT, def_sh_displacement, "DISPLACEMENT", Displacement, "Displacement", "" )
DefNode(ShaderNode, SH_NODE_VECTOR_DISPLACEMENT,def_sh_vector_displacement,"VECTOR_DISPLACEMENT",VectorDisplacement,"Vector Displacement","" )
DefNode(ShaderNode, SH_NODE_TEX_IES, def_sh_tex_ies, "TEX_IES", TexIES, "IES Texture", "" )
+DefNode(ShaderNode, SH_NODE_TEX_WHITE_NOISE, def_sh_tex_white_noise, "TEX_WHITE_NOISE", TexWhiteNoise, "White Noise", "" )
DefNode(CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
DefNode(CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 4891fb323ad..60a6cc91630 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -799,7 +799,7 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
nodeRemLink(ntree, displacement_link);
/* Convert displacement vector to bump height. */
- bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECT_MATH);
+ bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
bNodeSocket *normal_socket = ntree_shader_node_find_output(geo_node, "Normal");
dot_node->custom1 = 3; /* dot product */
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 2e8f81979a8..956b6057e5f 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -280,7 +280,7 @@ void node_shader_gpu_tex_mapping(GPUMaterial *mat,
tmat2 = GPU_uniform((float *)texmap->mat[2]);
tmat3 = GPU_uniform((float *)texmap->mat[3]);
- GPU_link(mat, "mapping", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
+ GPU_link(mat, "mapping_mat4", in[0].link, tmat0, tmat1, tmat2, tmat3, tmin, tmax, &in[0].link);
if (texmap->type == TEXMAP_TYPE_NORMAL) {
GPU_link(mat, "texco_norm", in[0].link, &in[0].link);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
index 2a371b7d184..741e792da87 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c
@@ -24,7 +24,17 @@
static bNodeSocketTemplate sh_node_bsdf_principled_in[] = {
{SOCK_RGBA, 1, N_("Base Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{SOCK_FLOAT, 1, N_("Subsurface"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
- {SOCK_VECTOR, 1, N_("Subsurface Radius"), 1.0f, 0.2f, 0.1f, 0.0f, 0.0f, 100.0f},
+ {SOCK_VECTOR,
+ 1,
+ N_("Subsurface Radius"),
+ 1.0f,
+ 0.2f,
+ 0.1f,
+ 0.0f,
+ 0.0f,
+ 100.0f,
+ PROP_NONE,
+ SOCK_COMPACT},
{SOCK_RGBA, 1, N_("Subsurface Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{SOCK_FLOAT, 1, N_("Metallic"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_FLOAT, 1, N_("Specular"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.c b/source/blender/nodes/shader/nodes/node_shader_clamp.c
new file mode 100644
index 00000000000..cfcd6a24aa5
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_clamp.c
@@ -0,0 +1,57 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.h"
+
+/* **************** Clamp ******************** */
+static bNodeSocketTemplate sh_node_clamp_in[] = {
+ {SOCK_FLOAT, 1, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {-1, 0, ""},
+};
+static bNodeSocketTemplate sh_node_clamp_out[] = {
+ {SOCK_FLOAT, 0, N_("Result")},
+ {-1, 0, ""},
+};
+
+static int gpu_shader_clamp(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ GPU_stack_link(mat, node, "clamp_value", in, out);
+ return 1;
+}
+
+void register_node_type_sh_clamp(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, sh_node_clamp_in, sh_node_clamp_out);
+ node_type_gpu(&ntype, gpu_shader_clamp);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.c b/source/blender/nodes/shader/nodes/node_shader_map_range.c
new file mode 100644
index 00000000000..c9ead0afbe2
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_map_range.c
@@ -0,0 +1,59 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.h"
+
+/* **************** Map Range ******************** */
+static bNodeSocketTemplate sh_node_map_range_in[] = {
+ {SOCK_FLOAT, 1, N_("Value"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("From Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("From Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("To Min"), 0.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("To Max"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {-1, 0, ""},
+};
+static bNodeSocketTemplate sh_node_map_range_out[] = {
+ {SOCK_FLOAT, 0, N_("Result")},
+ {-1, 0, ""},
+};
+
+static int gpu_shader_map_range(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ GPU_stack_link(mat, node, "map_range", in, out);
+ return 1;
+}
+
+void register_node_type_sh_map_range(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, sh_node_map_range_in, sh_node_map_range_out);
+ node_type_gpu(&ntype, gpu_shader_map_range);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c
index eca0d96f2c8..2f71bbf80b6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_mapping.c
+++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c
@@ -25,113 +25,50 @@
/* **************** MAPPING ******************** */
static bNodeSocketTemplate sh_node_mapping_in[] = {
- {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE},
+ {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE},
+ {SOCK_VECTOR, 1, N_("Location"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {SOCK_VECTOR, 1, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER},
+ {SOCK_VECTOR, 1, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_XYZ},
{-1, 0, ""},
};
static bNodeSocketTemplate sh_node_mapping_out[] = {
- {SOCK_VECTOR, 0, N_("Vector")},
+ {SOCK_VECTOR, 0, N_("Result")},
{-1, 0, ""},
};
-static void *node_shader_initexec_mapping(bNodeExecContext *UNUSED(context),
- bNode *node,
- bNodeInstanceKey UNUSED(key))
-{
- TexMapping *texmap = node->storage;
- BKE_texture_mapping_init(texmap);
- return NULL;
-}
-
-/* do the regular mapping options for blender textures */
-static void node_shader_exec_mapping(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- TexMapping *texmap = node->storage;
- float *vec = out[0]->vec;
-
- /* stack order input: vector */
- /* stack order output: vector */
- nodestack_get_vec(vec, SOCK_VECTOR, in[0]);
- mul_m4_v3(texmap->mat, vec);
-
- if (texmap->flag & TEXMAP_CLIP_MIN) {
- if (vec[0] < texmap->min[0]) {
- vec[0] = texmap->min[0];
- }
- if (vec[1] < texmap->min[1]) {
- vec[1] = texmap->min[1];
- }
- if (vec[2] < texmap->min[2]) {
- vec[2] = texmap->min[2];
- }
- }
- if (texmap->flag & TEXMAP_CLIP_MAX) {
- if (vec[0] > texmap->max[0]) {
- vec[0] = texmap->max[0];
- }
- if (vec[1] > texmap->max[1]) {
- vec[1] = texmap->max[1];
- }
- if (vec[2] > texmap->max[2]) {
- vec[2] = texmap->max[2];
- }
- }
-
- if (texmap->type == TEXMAP_TYPE_NORMAL) {
- normalize_v3(vec);
- }
-}
-
-static void node_shader_init_mapping(bNodeTree *UNUSED(ntree), bNode *node)
-{
- node->storage = BKE_texture_mapping_add(TEXMAP_TYPE_POINT);
-}
-
static int gpu_shader_mapping(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
GPUNodeStack *in,
GPUNodeStack *out)
{
- TexMapping *texmap = node->storage;
- float domin = (texmap->flag & TEXMAP_CLIP_MIN) != 0;
- float domax = (texmap->flag & TEXMAP_CLIP_MAX) != 0;
- static float max[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
- static float min[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
- GPUNodeLink *tmin, *tmax, *tmat0, *tmat1, *tmat2, *tmat3;
-
- tmin = GPU_uniform((domin) ? texmap->min : min);
- tmax = GPU_uniform((domax) ? texmap->max : max);
- tmat0 = GPU_uniform((float *)texmap->mat[0]);
- tmat1 = GPU_uniform((float *)texmap->mat[1]);
- tmat2 = GPU_uniform((float *)texmap->mat[2]);
- tmat3 = GPU_uniform((float *)texmap->mat[3]);
-
- GPU_stack_link(mat, node, "mapping", in, out, tmat0, tmat1, tmat2, tmat3, tmin, tmax);
-
- if (texmap->type == TEXMAP_TYPE_NORMAL) {
- GPU_link(mat, "texco_norm", out[0].link, &out[0].link);
- }
-
+ static const char *names[] = {
+ [NODE_MAPPING_TYPE_POINT] = "mapping_point",
+ [NODE_MAPPING_TYPE_TEXTURE] = "mapping_texture",
+ [NODE_MAPPING_TYPE_VECTOR] = "mapping_vector",
+ [NODE_MAPPING_TYPE_NORMAL] = "mapping_normal",
+ };
+
+ GPU_stack_link(mat, node, names[node->custom1], in, out);
return true;
}
+static void node_shader_update_mapping(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "Location");
+ nodeSetSocketAvailability(
+ sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE));
+}
+
void register_node_type_sh_mapping(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR, 0);
node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_mapping_out);
- node_type_size(&ntype, 320, 160, 360);
- node_type_init(&ntype, node_shader_init_mapping);
- node_type_storage(&ntype, "TexMapping", node_free_standard_storage, node_copy_standard_storage);
- node_type_exec(&ntype, node_shader_initexec_mapping, NULL, node_shader_exec_mapping);
node_type_gpu(&ntype, gpu_shader_mapping);
+ node_type_update(&ntype, node_shader_update_mapping);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c
index f0cd2273e67..0bd1e882f47 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.c
+++ b/source/blender/nodes/shader/nodes/node_shader_math.c
@@ -25,277 +25,11 @@
/* **************** SCALAR MATH ******************** */
static bNodeSocketTemplate sh_node_math_in[] = {
- {SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_FLOAT, 1, N_("Value"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("A"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("B"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{-1, 0, ""}};
-static bNodeSocketTemplate sh_node_math_out[] = {{SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}};
-
-static void node_shader_exec_math(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float a, b, r = 0.0f;
-
- nodestack_get_vec(&a, SOCK_FLOAT, in[0]);
- nodestack_get_vec(&b, SOCK_FLOAT, in[1]);
-
- switch (node->custom1) {
-
- case NODE_MATH_ADD:
- r = a + b;
- break;
- case NODE_MATH_SUB:
- r = a - b;
- break;
- case NODE_MATH_MUL:
- r = a * b;
- break;
- case NODE_MATH_DIVIDE: {
- if (b == 0) { /* We don't want to divide by zero. */
- r = 0.0;
- }
- else {
- r = a / b;
- }
- break;
- }
- case NODE_MATH_SIN: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = sinf(a);
- }
- else {
- r = sinf(b);
- }
- break;
- }
- case NODE_MATH_COS: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = cosf(a);
- }
- else {
- r = cosf(b);
- }
- break;
- }
- case NODE_MATH_TAN: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = tanf(a);
- }
- else {
- r = tanf(b);
- }
- break;
- }
- case NODE_MATH_ASIN: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- /* Can't do the impossible... */
- if (a <= 1 && a >= -1) {
- r = asinf(a);
- }
- else {
- r = 0.0;
- }
- }
- else {
- /* Can't do the impossible... */
- if (b <= 1 && b >= -1) {
- r = asinf(b);
- }
- else {
- r = 0.0;
- }
- }
- break;
- }
- case NODE_MATH_ACOS: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- /* Can't do the impossible... */
- if (a <= 1 && a >= -1) {
- r = acosf(a);
- }
- else {
- r = 0.0;
- }
- }
- else {
- /* Can't do the impossible... */
- if (b <= 1 && b >= -1) {
- r = acosf(b);
- }
- else {
- r = 0.0;
- }
- }
- break;
- }
- case NODE_MATH_ATAN: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = atan(a);
- }
- else {
- r = atan(b);
- }
- break;
- }
- case NODE_MATH_POW: {
- /* Only raise negative numbers by full integers */
- if (a >= 0) {
- r = pow(a, b);
- }
- else {
- float y_mod_1 = fabsf(fmodf(b, 1.0f));
-
- /* if input value is not nearly an integer,
- * fall back to zero, nicer than straight rounding. */
- if (y_mod_1 > 0.999f || y_mod_1 < 0.001f) {
- r = powf(a, floorf(b + 0.5f));
- }
- else {
- r = 0.0f;
- }
- }
-
- break;
- }
- case NODE_MATH_LOG: {
- /* Don't want any imaginary numbers... */
- if (a > 0 && b > 0) {
- r = log(a) / log(b);
- }
- else {
- r = 0.0;
- }
- break;
- }
- case NODE_MATH_MIN: {
- if (a < b) {
- r = a;
- }
- else {
- r = b;
- }
- break;
- }
- case NODE_MATH_MAX: {
- if (a > b) {
- r = a;
- }
- else {
- r = b;
- }
- break;
- }
- case NODE_MATH_ROUND: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = (a < 0) ? (int)(a - 0.5f) : (int)(a + 0.5f);
- }
- else {
- r = (b < 0) ? (int)(b - 0.5f) : (int)(b + 0.5f);
- }
- break;
- }
- case NODE_MATH_LESS: {
- if (a < b) {
- r = 1.0f;
- }
- else {
- r = 0.0f;
- }
- break;
- }
- case NODE_MATH_GREATER: {
- if (a > b) {
- r = 1.0f;
- }
- else {
- r = 0.0f;
- }
- break;
- }
- case NODE_MATH_MOD: {
- if (b == 0.0f) {
- r = 0.0f;
- }
- else {
- r = fmod(a, b);
- }
- break;
- }
- case NODE_MATH_ABS: {
- r = fabsf(a);
- break;
- }
- case NODE_MATH_ATAN2: {
- r = atan2(a, b);
- break;
- }
- case NODE_MATH_FLOOR: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = floorf(a);
- }
- else {
- r = floorf(b);
- }
- break;
- }
- case NODE_MATH_CEIL: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = ceilf(a);
- }
- else {
- r = ceilf(b);
- }
- break;
- }
- case NODE_MATH_FRACT: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- r = a - floorf(a);
- }
- else {
- r = b - floorf(b);
- }
- break;
- }
- case NODE_MATH_SQRT: {
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- if (a > 0) {
- r = sqrt(a);
- }
- else {
- r = 0.0;
- }
- }
- else {
- if (b > 0) {
- r = sqrt(b);
- }
- else {
- r = 0.0;
- }
- }
- break;
- }
- }
- if (node->custom2 & SHD_MATH_CLAMP) {
- CLAMP(r, 0.0f, 1.0f);
- }
- out[0]->vec[0] = r;
-}
+static bNodeSocketTemplate sh_node_math_out[] = {{SOCK_FLOAT, 0, N_("Result")}, {-1, 0, ""}};
static int gpu_shader_math(GPUMaterial *mat,
bNode *node,
@@ -304,68 +38,60 @@ static int gpu_shader_math(GPUMaterial *mat,
GPUNodeStack *out)
{
static const char *names[] = {
- "math_add", "math_subtract", "math_multiply", "math_divide", "math_sine",
- "math_cosine", "math_tangent", "math_asin", "math_acos", "math_atan",
- "math_pow", "math_log", "math_min", "math_max", "math_round",
- "math_less_than", "math_greater_than", "math_modulo", "math_abs", "math_atan2",
- "math_floor", "math_ceil", "math_fract", "math_sqrt",
+ [NODE_MATH_ADD] = "math_add",
+ [NODE_MATH_SUBTRACT] = "math_subtract",
+ [NODE_MATH_MULTIPLY] = "math_multiply",
+ [NODE_MATH_DIVIDE] = "math_divide",
+
+ [NODE_MATH_POWER] = "math_power",
+ [NODE_MATH_LOGARITHM] = "math_logarithm",
+ [NODE_MATH_SQRT] = "math_sqrt",
+ [NODE_MATH_ABSOLUTE] = "math_absolute",
+
+ [NODE_MATH_MINIMUM] = "math_minimum",
+ [NODE_MATH_MAXIMUM] = "math_maximum",
+ [NODE_MATH_LESS_THAN] = "math_less_than",
+ [NODE_MATH_GREATER_THAN] = "math_greater_than",
+
+ [NODE_MATH_ROUND] = "math_round",
+ [NODE_MATH_FLOOR] = "math_floor",
+ [NODE_MATH_CEIL] = "math_ceil",
+ [NODE_MATH_FRACTION] = "math_fraction",
+ [NODE_MATH_MODULO] = "math_modulo",
+
+ [NODE_MATH_SINE] = "math_sine",
+ [NODE_MATH_COSINE] = "math_cosine",
+ [NODE_MATH_TANGENT] = "math_tangent",
+ [NODE_MATH_ARCSINE] = "math_arcsine",
+ [NODE_MATH_ARCCOSINE] = "math_arccosine",
+ [NODE_MATH_ARCTANGENT] = "math_arctangent",
+ [NODE_MATH_ARCTAN2] = "math_arctan2",
};
- switch (node->custom1) {
- case NODE_MATH_ADD:
- case NODE_MATH_SUB:
- case NODE_MATH_MUL:
- case NODE_MATH_DIVIDE:
- case NODE_MATH_POW:
- case NODE_MATH_LOG:
- case NODE_MATH_MIN:
- case NODE_MATH_MAX:
- case NODE_MATH_LESS:
- case NODE_MATH_GREATER:
- case NODE_MATH_MOD:
- case NODE_MATH_ATAN2:
- GPU_stack_link(mat, node, names[node->custom1], in, out);
- break;
- case NODE_MATH_SIN:
- case NODE_MATH_COS:
- case NODE_MATH_TAN:
- case NODE_MATH_ASIN:
- case NODE_MATH_ACOS:
- case NODE_MATH_ATAN:
- case NODE_MATH_ROUND:
- case NODE_MATH_ABS:
- case NODE_MATH_FLOOR:
- case NODE_MATH_FRACT:
- case NODE_MATH_CEIL:
- case NODE_MATH_SQRT:
- if (in[0].hasinput || !in[1].hasinput) {
- /* use only first item and terminator */
- GPUNodeStack tmp_in[2];
- memcpy(&tmp_in[0], &in[0], sizeof(GPUNodeStack));
- memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
- GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
- }
- else {
- /* use only second item and terminator */
- GPUNodeStack tmp_in[2];
- memcpy(&tmp_in[0], &in[1], sizeof(GPUNodeStack));
- memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
- GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
- }
- break;
- default:
- return 0;
- }
-
- if (node->custom2 & SHD_MATH_CLAMP) {
- float min[3] = {0.0f, 0.0f, 0.0f};
- float max[3] = {1.0f, 1.0f, 1.0f};
- GPU_link(mat, "clamp_val", out[0].link, GPU_constant(min), GPU_constant(max), &out[0].link);
- }
-
+ GPU_stack_link(mat, node, names[node->custom1], in, out);
return 1;
}
+static void node_shader_update_math(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "B");
+
+ nodeSetSocketAvailability(sock,
+ !ELEM(node->custom1,
+ NODE_MATH_SQRT,
+ NODE_MATH_CEIL,
+ NODE_MATH_SINE,
+ NODE_MATH_ROUND,
+ NODE_MATH_FLOOR,
+ NODE_MATH_COSINE,
+ NODE_MATH_ARCSINE,
+ NODE_MATH_TANGENT,
+ NODE_MATH_ABSOLUTE,
+ NODE_MATH_FRACTION,
+ NODE_MATH_ARCCOSINE,
+ NODE_MATH_ARCTANGENT));
+}
+
void register_node_type_sh_math(void)
{
static bNodeType ntype;
@@ -373,9 +99,8 @@ void register_node_type_sh_math(void)
sh_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_math_in, sh_node_math_out);
node_type_label(&ntype, node_math_label);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_math);
node_type_gpu(&ntype, gpu_shader_math);
+ node_type_update(&ntype, node_shader_update_math);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.c
index 118b8136693..58449a53706 100644
--- a/source/blender/nodes/shader/nodes/node_shader_object_info.c
+++ b/source/blender/nodes/shader/nodes/node_shader_object_info.c
@@ -23,6 +23,7 @@
static bNodeSocketTemplate sh_node_object_info_out[] = {
{SOCK_VECTOR, 0, N_("Location"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ {SOCK_RGBA, 0, N_("Color"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{SOCK_FLOAT, 0, N_("Object Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{SOCK_FLOAT, 0, N_("Material Index"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{SOCK_FLOAT, 0, N_("Random"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
@@ -36,38 +37,25 @@ static int node_shader_gpu_object_info(GPUMaterial *mat,
GPUNodeStack *out)
{
Material *ma = GPU_material_get_material(mat);
- /* Convert to float. */
- float index = ma ? ma->index : 0;
+ float index = ma ? ma->index : 0.0f;
return GPU_stack_link(mat,
node,
"node_object_info",
in,
out,
GPU_builtin(GPU_OBJECT_MATRIX),
+ GPU_builtin(GPU_OBJECT_COLOR),
GPU_builtin(GPU_OBJECT_INFO),
GPU_constant(&index));
}
-static void node_shader_exec_object_info(void *UNUSED(data),
- int UNUSED(thread),
- bNode *UNUSED(node),
- bNodeExecData *UNUSED(execdata),
- bNodeStack **UNUSED(in),
- bNodeStack **UNUSED(out))
-{
-}
-
-/* node type definition */
void register_node_type_sh_object_info(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0);
node_type_socket_templates(&ntype, NULL, sh_node_object_info_out);
- node_type_init(&ntype, NULL);
- node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_object_info);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_object_info);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
index f1b4a0e9fe3..21e07ece7b9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
@@ -24,7 +24,7 @@
static bNodeSocketTemplate sh_node_subsurface_scattering_in[] = {
{SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
{SOCK_FLOAT, 1, N_("Scale"), 1.0, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
- {SOCK_VECTOR, 1, N_("Radius"), 1.0f, 0.2f, 0.1f, 0.0f, 0.0f, 100.0f},
+ {SOCK_VECTOR, 1, N_("Radius"), 1.0f, 0.2f, 0.1f, 0.0f, 0.0f, 100.0f, PROP_NONE, SOCK_COMPACT},
{SOCK_FLOAT, 1, N_("Sharpness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_FLOAT, 1, N_("Texture Blur"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{SOCK_VECTOR,
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
index 250a1da3c23..cd332d6f1d4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.c
@@ -23,6 +23,7 @@
static bNodeSocketTemplate sh_node_tex_musgrave_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_FLOAT, 1, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Detail"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 16.0f},
{SOCK_FLOAT, 1, N_("Dimension"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
@@ -33,17 +34,6 @@ static bNodeSocketTemplate sh_node_tex_musgrave_in[] = {
};
static bNodeSocketTemplate sh_node_tex_musgrave_out[] = {
- {SOCK_RGBA,
- 0,
- N_("Color"),
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 0.0f,
- 1.0f,
- PROP_NONE,
- SOCK_NO_INTERNAL_LINK},
{SOCK_FLOAT,
0,
N_("Fac"),
@@ -64,6 +54,7 @@ static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
tex->musgrave_type = SHD_MUSGRAVE_FBM;
+ tex->dimensions = 3;
node->storage = tex;
}
@@ -82,9 +73,75 @@ static int node_shader_gpu_tex_musgrave(GPUMaterial *mat,
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
- float type = tex->musgrave_type;
+ int dimensions = tex->dimensions;
+ int type = tex->musgrave_type;
+
+ static const char *names[][5] = {
+ [SHD_MUSGRAVE_MULTIFRACTAL] =
+ {
+ "",
+ "node_tex_musgrave_multi_fractal_1d",
+ "node_tex_musgrave_multi_fractal_2d",
+ "node_tex_musgrave_multi_fractal_3d",
+ "node_tex_musgrave_multi_fractal_4d",
+ },
+ [SHD_MUSGRAVE_FBM] =
+ {
+ "",
+ "node_tex_musgrave_fBm_1d",
+ "node_tex_musgrave_fBm_2d",
+ "node_tex_musgrave_fBm_3d",
+ "node_tex_musgrave_fBm_4d",
+ },
+ [SHD_MUSGRAVE_HYBRID_MULTIFRACTAL] =
+ {
+ "",
+ "node_tex_musgrave_hybrid_multi_fractal_1d",
+ "node_tex_musgrave_hybrid_multi_fractal_2d",
+ "node_tex_musgrave_hybrid_multi_fractal_3d",
+ "node_tex_musgrave_hybrid_multi_fractal_4d",
+ },
+ [SHD_MUSGRAVE_RIDGED_MULTIFRACTAL] =
+ {
+ "",
+ "node_tex_musgrave_ridged_multi_fractal_1d",
+ "node_tex_musgrave_ridged_multi_fractal_2d",
+ "node_tex_musgrave_ridged_multi_fractal_3d",
+ "node_tex_musgrave_ridged_multi_fractal_4d",
+ },
+ [SHD_MUSGRAVE_HETERO_TERRAIN] =
+ {
+ "",
+ "node_tex_musgrave_hetero_terrain_1d",
+ "node_tex_musgrave_hetero_terrain_2d",
+ "node_tex_musgrave_hetero_terrain_3d",
+ "node_tex_musgrave_hetero_terrain_4d",
+ },
+ };
+
+ BLI_assert(type >= 0 && type < 5);
+ BLI_assert(dimensions > 0 && dimensions < 5);
+
+ return GPU_stack_link(mat, node, names[type][dimensions], in, out);
+}
+
+static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage;
+
+ bNodeSocket *inVecSock = BLI_findlink(&node->inputs, 0);
+ bNodeSocket *inWSock = BLI_findlink(&node->inputs, 1);
+ bNodeSocket *inOffsetSock = BLI_findlink(&node->inputs, 6);
+ bNodeSocket *inGainSock = BLI_findlink(&node->inputs, 7);
- return GPU_stack_link(mat, node, "node_tex_musgrave", in, out, GPU_constant(&type));
+ nodeSetSocketAvailability(inVecSock, tex->dimensions != 1);
+ nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4);
+ nodeSetSocketAvailability(inOffsetSock,
+ tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL &&
+ tex->musgrave_type != SHD_MUSGRAVE_FBM);
+ nodeSetSocketAvailability(inGainSock,
+ tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL &&
+ tex->musgrave_type != SHD_MUSGRAVE_RIDGED_MULTIFRACTAL);
}
/* node type definition */
@@ -99,6 +156,7 @@ void register_node_type_sh_tex_musgrave(void)
node_type_storage(
&ntype, "NodeTexMusgrave", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_musgrave);
+ node_type_update(&ntype, node_shader_update_tex_musgrave);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
index 34c4b17f255..1b71287834d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.c
@@ -23,6 +23,7 @@
static bNodeSocketTemplate sh_node_tex_noise_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_FLOAT, 1, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Detail"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, 16.0f},
{SOCK_FLOAT, 1, N_("Distortion"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
@@ -30,27 +31,27 @@ static bNodeSocketTemplate sh_node_tex_noise_in[] = {
};
static bNodeSocketTemplate sh_node_tex_noise_out[] = {
- {SOCK_RGBA,
+ {SOCK_FLOAT,
0,
- N_("Color"),
+ N_("Value"),
0.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
- PROP_NONE,
+ PROP_FACTOR,
SOCK_NO_INTERNAL_LINK},
- {SOCK_FLOAT,
+ {SOCK_RGBA,
0,
- N_("Fac"),
+ N_("Color"),
0.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
- PROP_FACTOR,
+ PROP_NONE,
SOCK_NO_INTERNAL_LINK},
{-1, 0, ""},
};
@@ -60,6 +61,7 @@ static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
NodeTexNoise *tex = MEM_callocN(sizeof(NodeTexNoise), "NodeTexNoise");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
+ tex->dimensions = 3;
node->storage = tex;
}
@@ -77,7 +79,29 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat,
node_shader_gpu_tex_mapping(mat, node, in, out);
- return GPU_stack_link(mat, node, "node_tex_noise", in, out);
+ NodeTexNoise *tex = (NodeTexNoise *)node->storage;
+ switch (tex->dimensions) {
+ case 1:
+ return GPU_stack_link(mat, node, "node_noise_texture_1d", in, out);
+ case 2:
+ return GPU_stack_link(mat, node, "node_noise_texture_2d", in, out);
+ case 3:
+ return GPU_stack_link(mat, node, "node_noise_texture_3d", in, out);
+ case 4:
+ return GPU_stack_link(mat, node, "node_noise_texture_4d", in, out);
+ default:
+ return 0;
+ }
+}
+
+static void node_shader_update_tex_noise(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
+ bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W");
+
+ NodeTexNoise *tex = (NodeTexNoise *)node->storage;
+ nodeSetSocketAvailability(sockVector, tex->dimensions != 1);
+ nodeSetSocketAvailability(sockW, tex->dimensions == 1 || tex->dimensions == 4);
}
/* node type definition */
@@ -91,6 +115,7 @@ void register_node_type_sh_tex_noise(void)
node_type_storage(
&ntype, "NodeTexNoise", node_free_standard_storage, node_copy_standard_storage);
node_type_gpu(&ntype, node_shader_gpu_tex_noise);
+ node_type_update(&ntype, node_shader_update_tex_noise);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
index e0b4de985d8..e3e93c8dab4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.c
@@ -23,12 +23,26 @@
static bNodeSocketTemplate sh_node_tex_voronoi_in[] = {
{SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
+ {SOCK_FLOAT, 1, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
{SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
+ {SOCK_FLOAT, 1, N_("Smoothness"), 5.0f, 0.0f, 0.0f, 0.0f, 3.5f, 75.0f},
{SOCK_FLOAT, 1, N_("Exponent"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 32.0f},
+ {SOCK_FLOAT, 1, N_("Jitter"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{-1, 0, ""},
};
static bNodeSocketTemplate sh_node_tex_voronoi_out[] = {
+ {SOCK_FLOAT,
+ 0,
+ N_("Distance"),
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ PROP_NONE,
+ SOCK_NO_INTERNAL_LINK},
{SOCK_RGBA,
0,
N_("Color"),
@@ -40,16 +54,28 @@ static bNodeSocketTemplate sh_node_tex_voronoi_out[] = {
1.0f,
PROP_NONE,
SOCK_NO_INTERNAL_LINK},
+ {SOCK_VECTOR,
+ 0,
+ N_("Position"),
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ PROP_NONE,
+ SOCK_NO_INTERNAL_LINK},
+ {SOCK_FLOAT, 0, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK},
{SOCK_FLOAT,
0,
- N_("Fac"),
+ N_("Radius"),
0.0f,
0.0f,
0.0f,
0.0f,
0.0f,
1.0f,
- PROP_FACTOR,
+ PROP_NONE,
SOCK_NO_INTERNAL_LINK},
{-1, 0, ""},
};
@@ -59,8 +85,8 @@ static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
NodeTexVoronoi *tex = MEM_callocN(sizeof(NodeTexVoronoi), "NodeTexVoronoi");
BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT);
BKE_texture_colormapping_default(&tex->base.color_mapping);
- tex->coloring = SHD_VORONOI_INTENSITY;
- tex->distance = SHD_VORONOI_DISTANCE;
+ tex->dimensions = 3;
+ tex->distance = SHD_VORONOI_EUCLIDEAN;
tex->feature = SHD_VORONOI_F1;
node->storage = tex;
@@ -76,42 +102,131 @@ static int node_shader_gpu_tex_voronoi(GPUMaterial *mat,
in[0].link = GPU_attribute(CD_ORCO, "");
GPU_link(mat, "generated_texco", GPU_builtin(GPU_VIEW_POSITION), in[0].link, &in[0].link);
}
-
node_shader_gpu_tex_mapping(mat, node, in, out);
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
- float coloring = tex->coloring;
float metric = tex->distance;
- float feature = tex->feature;
-
- return GPU_stack_link(mat,
- node,
- "node_tex_voronoi",
- in,
- out,
- GPU_constant(&coloring),
- GPU_constant(&metric),
- GPU_constant(&feature));
+
+ switch (tex->dimensions) {
+ case 1:
+ switch (tex->feature) {
+ case SHD_VORONOI_F1:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_f1_1d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_SMOOTH_F1:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_smooth_f1_1d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_F2:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_f2_1d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_DISTANCE_TO_EDGE:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_distance_to_edge_1d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_N_SPHERE_RADIUS:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_n_sphere_radius_1d", in, out, GPU_constant(&metric));
+ default:
+ return 0;
+ }
+ case 2:
+ switch (tex->feature) {
+ case SHD_VORONOI_F1:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_f1_2d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_SMOOTH_F1:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_smooth_f1_2d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_F2:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_f2_2d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_DISTANCE_TO_EDGE:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_distance_to_edge_2d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_N_SPHERE_RADIUS:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_n_sphere_radius_2d", in, out, GPU_constant(&metric));
+ default:
+ return 0;
+ }
+ case 3:
+ switch (tex->feature) {
+ case SHD_VORONOI_F1:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_f1_3d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_SMOOTH_F1:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_smooth_f1_3d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_F2:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_f2_3d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_DISTANCE_TO_EDGE:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_distance_to_edge_3d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_N_SPHERE_RADIUS:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_n_sphere_radius_3d", in, out, GPU_constant(&metric));
+ default:
+ return 0;
+ }
+ case 4:
+ switch (tex->feature) {
+ case SHD_VORONOI_F1:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_f1_4d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_SMOOTH_F1:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_smooth_f1_4d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_F2:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_f2_4d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_DISTANCE_TO_EDGE:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_distance_to_edge_4d", in, out, GPU_constant(&metric));
+ case SHD_VORONOI_N_SPHERE_RADIUS:
+ return GPU_stack_link(
+ mat, node, "node_tex_voronoi_n_sphere_radius_4d", in, out, GPU_constant(&metric));
+ default:
+ return 0;
+ }
+ default:
+ return 0;
+ }
}
static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node)
{
NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage;
- bNodeSocket *sock;
- for (sock = node->inputs.first; sock; sock = sock->next) {
- if (STREQ(sock->name, "Exponent")) {
- if (tex->distance == SHD_VORONOI_MINKOWSKI) {
- sock->flag &= ~SOCK_UNAVAIL;
- }
- else {
- sock->flag |= SOCK_UNAVAIL;
- }
- }
- }
+ bNodeSocket *inVecSock = BLI_findlink(&node->inputs, 0);
+ bNodeSocket *inWSock = BLI_findlink(&node->inputs, 1);
+ bNodeSocket *inSmoothnessSock = BLI_findlink(&node->inputs, 3);
+ bNodeSocket *inExponentSock = BLI_findlink(&node->inputs, 4);
+
+ bNodeSocket *outDistanceSock = BLI_findlink(&node->outputs, 0);
+ bNodeSocket *outColorSock = BLI_findlink(&node->outputs, 1);
+ bNodeSocket *outPositionSock = BLI_findlink(&node->outputs, 2);
+ bNodeSocket *outWSock = BLI_findlink(&node->outputs, 3);
+ bNodeSocket *outRadiusSock = BLI_findlink(&node->outputs, 4);
+
+ nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4);
+ nodeSetSocketAvailability(inVecSock, tex->dimensions != 1);
+ nodeSetSocketAvailability(inExponentSock, tex->distance == SHD_VORONOI_MINKOWSKI);
+ nodeSetSocketAvailability(inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1);
+ nodeSetSocketAvailability(outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ nodeSetSocketAvailability(outColorSock,
+ tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ tex->feature != SHD_VORONOI_N_SPHERE_RADIUS);
+ nodeSetSocketAvailability(outPositionSock,
+ tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ tex->dimensions != 1);
+ nodeSetSocketAvailability(outWSock,
+ tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE &&
+ tex->feature != SHD_VORONOI_N_SPHERE_RADIUS &&
+ (tex->dimensions == 1 || tex->dimensions == 4));
+ nodeSetSocketAvailability(outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS);
}
-/* node type definition */
void register_node_type_sh_tex_voronoi(void)
{
static bNodeType ntype;
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c
new file mode 100644
index 00000000000..ec2047e2d2f
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c
@@ -0,0 +1,77 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** WHITE NOISE **************** */
+
+static bNodeSocketTemplate sh_node_tex_white_noise_in[] = {
+ {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("W"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {-1, 0, ""}};
+
+static bNodeSocketTemplate sh_node_tex_white_noise_out[] = {
+ {SOCK_FLOAT, 0, N_("Value")},
+ {-1, 0, ""},
+};
+
+static void node_shader_init_tex_white_noise(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = 3;
+}
+
+static int gpu_shader_tex_white_noise(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ static const char *names[] = {
+ "",
+ "node_white_noise_1d",
+ "node_white_noise_2d",
+ "node_white_noise_3d",
+ "node_white_noise_4d",
+ };
+
+ GPU_stack_link(mat, node, names[node->custom1], in, out);
+ return true;
+}
+
+static void node_shader_update_tex_white_noise(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector");
+ bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W");
+
+ nodeSetSocketAvailability(sockVector, node->custom1 != 1);
+ nodeSetSocketAvailability(sockW, node->custom1 == 1 || node->custom1 == 4);
+}
+
+void register_node_type_sh_tex_white_noise(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE, 0);
+ node_type_socket_templates(&ntype, sh_node_tex_white_noise_in, sh_node_tex_white_noise_out);
+ node_type_init(&ntype, node_shader_init_tex_white_noise);
+ node_type_gpu(&ntype, gpu_shader_tex_white_noise);
+ node_type_update(&ntype, node_shader_update_tex_white_noise);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectMath.c b/source/blender/nodes/shader/nodes/node_shader_vectMath.c
index 41273a6dc1d..6a4fcd01181 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectMath.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vectMath.c
@@ -25,75 +25,14 @@
/* **************** VECTOR MATH ******************** */
static bNodeSocketTemplate sh_node_vect_math_in[] = {
- {SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_VECTOR, 1, N_("A"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_VECTOR, 1, N_("B"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+ {SOCK_FLOAT, 1, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
{-1, 0, ""}};
static bNodeSocketTemplate sh_node_vect_math_out[] = {
{SOCK_VECTOR, 0, N_("Vector")}, {SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}};
-static void node_shader_exec_vect_math(void *UNUSED(data),
- int UNUSED(thread),
- bNode *node,
- bNodeExecData *UNUSED(execdata),
- bNodeStack **in,
- bNodeStack **out)
-{
- float vec1[3], vec2[3];
-
- nodestack_get_vec(vec1, SOCK_VECTOR, in[0]);
- nodestack_get_vec(vec2, SOCK_VECTOR, in[1]);
-
- if (node->custom1 == 0) { /* Add */
- out[0]->vec[0] = vec1[0] + vec2[0];
- out[0]->vec[1] = vec1[1] + vec2[1];
- out[0]->vec[2] = vec1[2] + vec2[2];
-
- out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) /
- 3.0f;
- }
- else if (node->custom1 == 1) { /* Subtract */
- out[0]->vec[0] = vec1[0] - vec2[0];
- out[0]->vec[1] = vec1[1] - vec2[1];
- out[0]->vec[2] = vec1[2] - vec2[2];
-
- out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) /
- 3.0f;
- }
- else if (node->custom1 == 2) { /* Average */
- out[0]->vec[0] = vec1[0] + vec2[0];
- out[0]->vec[1] = vec1[1] + vec2[1];
- out[0]->vec[2] = vec1[2] + vec2[2];
-
- out[1]->vec[0] = normalize_v3(out[0]->vec);
- }
- else if (node->custom1 == 3) { /* Dot product */
- out[1]->vec[0] = (vec1[0] * vec2[0]) + (vec1[1] * vec2[1]) + (vec1[2] * vec2[2]);
- }
- else if (node->custom1 == 4) { /* Cross product */
- out[0]->vec[0] = (vec1[1] * vec2[2]) - (vec1[2] * vec2[1]);
- out[0]->vec[1] = (vec1[2] * vec2[0]) - (vec1[0] * vec2[2]);
- out[0]->vec[2] = (vec1[0] * vec2[1]) - (vec1[1] * vec2[0]);
-
- out[1]->vec[0] = normalize_v3(out[0]->vec);
- }
- else if (node->custom1 == 5) { /* Normalize */
- /* This one only takes one input, so we've got to choose. */
- if (in[0]->hasinput || !in[1]->hasinput) {
- out[0]->vec[0] = vec1[0];
- out[0]->vec[1] = vec1[1];
- out[0]->vec[2] = vec1[2];
- }
- else {
- out[0]->vec[0] = vec2[0];
- out[0]->vec[1] = vec2[1];
- out[0]->vec[2] = vec2[2];
- }
-
- out[1]->vec[0] = normalize_v3(out[0]->vec);
- }
-}
-
static int gpu_shader_vect_math(GPUMaterial *mat,
bNode *node,
bNodeExecData *UNUSED(execdata),
@@ -101,55 +40,74 @@ static int gpu_shader_vect_math(GPUMaterial *mat,
GPUNodeStack *out)
{
static const char *names[] = {
- "vec_math_add",
- "vec_math_sub",
- "vec_math_average",
- "vec_math_dot",
- "vec_math_cross",
- "vec_math_normalize",
+ [NODE_VECTOR_MATH_ADD] = "vec_math_add",
+ [NODE_VECTOR_MATH_SUBTRACT] = "vec_math_subtract",
+ [NODE_VECTOR_MATH_MULTIPLY] = "vec_math_multiply",
+ [NODE_VECTOR_MATH_DIVIDE] = "vec_math_divide",
+
+ [NODE_VECTOR_MATH_CROSS_PRODUCT] = "vec_math_cross",
+ [NODE_VECTOR_MATH_PROJECT] = "vec_math_project",
+ [NODE_VECTOR_MATH_REFLECT] = "vec_math_reflect",
+ [NODE_VECTOR_MATH_DOT_PRODUCT] = "vec_math_dot",
+
+ [NODE_VECTOR_MATH_DISTANCE] = "vec_math_distance",
+ [NODE_VECTOR_MATH_LENGTH] = "vec_math_length",
+ [NODE_VECTOR_MATH_SCALE] = "vec_math_scale",
+ [NODE_VECTOR_MATH_NORMALIZE] = "vec_math_normalize",
+
+ [NODE_VECTOR_MATH_SNAP] = "vec_math_snap",
+ [NODE_VECTOR_MATH_FLOOR] = "vec_math_floor",
+ [NODE_VECTOR_MATH_CEIL] = "vec_math_ceil",
+ [NODE_VECTOR_MATH_MODULO] = "vec_math_modulo",
+ [NODE_VECTOR_MATH_FRACTION] = "vec_math_fraction",
+ [NODE_VECTOR_MATH_ABSOLUTE] = "vec_math_absolute",
+ [NODE_VECTOR_MATH_MINIMUM] = "vec_math_minimum",
+ [NODE_VECTOR_MATH_MAXIMUM] = "vec_math_maximum",
};
- switch (node->custom1) {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- GPU_stack_link(mat, node, names[node->custom1], in, out);
- break;
- case 5:
- if (in[0].hasinput || !in[1].hasinput) {
- /* use only first item and terminator */
- GPUNodeStack tmp_in[2];
- memcpy(&tmp_in[0], &in[0], sizeof(GPUNodeStack));
- memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
- GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
- }
- else {
- /* use only second item and terminator */
- GPUNodeStack tmp_in[2];
- memcpy(&tmp_in[0], &in[1], sizeof(GPUNodeStack));
- memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
- GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
- }
- break;
- default:
- return false;
- }
-
+ GPU_stack_link(mat, node, names[node->custom1], in, out);
return true;
}
+static void node_shader_update_vec_math(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ bNodeSocket *sockB = nodeFindSocket(node, SOCK_IN, "B");
+ bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale");
+
+ bNodeSocket *sockVector = nodeFindSocket(node, SOCK_OUT, "Vector");
+ bNodeSocket *sockValue = nodeFindSocket(node, SOCK_OUT, "Value");
+
+ nodeSetSocketAvailability(sockB,
+ !ELEM(node->custom1,
+ NODE_VECTOR_MATH_CEIL,
+ NODE_VECTOR_MATH_SCALE,
+ NODE_VECTOR_MATH_FLOOR,
+ NODE_VECTOR_MATH_LENGTH,
+ NODE_VECTOR_MATH_ABSOLUTE,
+ NODE_VECTOR_MATH_FRACTION,
+ NODE_VECTOR_MATH_NORMALIZE));
+ nodeSetSocketAvailability(sockScale, node->custom1 == NODE_VECTOR_MATH_SCALE);
+ nodeSetSocketAvailability(sockVector,
+ !ELEM(node->custom1,
+ NODE_VECTOR_MATH_LENGTH,
+ NODE_VECTOR_MATH_DISTANCE,
+ NODE_VECTOR_MATH_DOT_PRODUCT));
+ nodeSetSocketAvailability(sockValue,
+ ELEM(node->custom1,
+ NODE_VECTOR_MATH_LENGTH,
+ NODE_VECTOR_MATH_DISTANCE,
+ NODE_VECTOR_MATH_DOT_PRODUCT));
+}
+
void register_node_type_sh_vect_math(void)
{
static bNodeType ntype;
- sh_node_type_base(&ntype, SH_NODE_VECT_MATH, "Vector Math", NODE_CLASS_CONVERTOR, 0);
+ sh_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, sh_node_vect_math_in, sh_node_vect_math_out);
node_type_label(&ntype, node_vect_math_label);
- node_type_storage(&ntype, "", NULL, NULL);
- node_type_exec(&ntype, NULL, NULL, node_shader_exec_vect_math);
node_type_gpu(&ntype, gpu_shader_vect_math);
+ node_type_update(&ntype, node_shader_update_vec_math);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c b/source/blender/nodes/shader/nodes/node_shader_vertex_color.c
new file mode 100644
index 00000000000..8848fc37c66
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.c
@@ -0,0 +1,58 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "../node_shader_util.h"
+
+static bNodeSocketTemplate sh_node_vertex_color_out[] = {
+ {SOCK_RGBA, 0, N_("Color")},
+ {SOCK_FLOAT, 0, N_("Alpha")},
+ {-1, 0, ""},
+};
+
+static void node_shader_init_vertex_color(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeShaderVertexColor *vertexColor = MEM_callocN(sizeof(NodeShaderVertexColor),
+ "NodeShaderVertexColor");
+ node->storage = vertexColor;
+}
+
+static int node_shader_gpu_vertex_color(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+ NodeShaderVertexColor *vertexColor = (NodeShaderVertexColor *)node->storage;
+ GPUNodeLink *vertexColorLink = GPU_attribute(CD_MCOL, vertexColor->layer_name);
+ return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink);
+}
+
+void register_node_type_sh_vertex_color(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Vertex Color", NODE_CLASS_INPUT, 0);
+ node_type_socket_templates(&ntype, NULL, sh_node_vertex_color_out);
+ node_type_init(&ntype, node_shader_init_vertex_color);
+ node_type_storage(
+ &ntype, "NodeShaderVertexColor", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, node_shader_gpu_vertex_color);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_info.c b/source/blender/nodes/shader/nodes/node_shader_volume_info.c
new file mode 100644
index 00000000000..98c44dd590b
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_volume_info.c
@@ -0,0 +1,56 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+#include "../node_shader_util.h"
+
+static bNodeSocketTemplate sh_node_volume_info_out[] = {
+ {SOCK_RGBA, 0, N_("Color")},
+ {SOCK_FLOAT, 0, N_("Density")},
+ {SOCK_FLOAT, 0, N_("Flame")},
+ {SOCK_FLOAT, 0, N_("Temperature")},
+ {-1, 0, ""},
+};
+
+static int node_shader_gpu_volume_info(GPUMaterial *mat,
+ bNode *node,
+ bNodeExecData *UNUSED(execdata),
+ GPUNodeStack *in,
+ GPUNodeStack *out)
+{
+
+ return GPU_stack_link(mat,
+ node,
+ "node_volume_info",
+ in,
+ out,
+ GPU_builtin(GPU_VOLUME_DENSITY),
+ GPU_builtin(GPU_VOLUME_FLAME),
+ GPU_builtin(GPU_VOLUME_TEMPERATURE));
+}
+
+void register_node_type_sh_volume_info(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_VOLUME_INFO, "Volume Info", NODE_CLASS_INPUT, 0);
+ node_type_socket_templates(&ntype, NULL, sh_node_volume_info_out);
+ node_type_gpu(&ntype, node_shader_gpu_volume_info);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c
index 2eb32e0addc..b1d67a5a953 100644
--- a/source/blender/nodes/texture/nodes/node_texture_math.c
+++ b/source/blender/nodes/texture/nodes/node_texture_math.c
@@ -46,10 +46,10 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
case NODE_MATH_ADD:
*out = in0 + in1;
break;
- case NODE_MATH_SUB:
+ case NODE_MATH_SUBTRACT:
*out = in0 - in1;
break;
- case NODE_MATH_MUL:
+ case NODE_MATH_MULTIPLY:
*out = in0 * in1;
break;
case NODE_MATH_DIVIDE: {
@@ -62,19 +62,19 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
break;
}
- case NODE_MATH_SIN: {
+ case NODE_MATH_SINE: {
*out = sinf(in0);
break;
}
- case NODE_MATH_COS: {
+ case NODE_MATH_COSINE: {
*out = cosf(in0);
break;
}
- case NODE_MATH_TAN: {
+ case NODE_MATH_TANGENT: {
*out = tanf(in0);
break;
}
- case NODE_MATH_ASIN: {
+ case NODE_MATH_ARCSINE: {
/* Can't do the impossible... */
if (in0 <= 1 && in0 >= -1) {
*out = asinf(in0);
@@ -84,7 +84,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
break;
}
- case NODE_MATH_ACOS: {
+ case NODE_MATH_ARCCOSINE: {
/* Can't do the impossible... */
if (in0 <= 1 && in0 >= -1) {
*out = acosf(in0);
@@ -94,11 +94,11 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
break;
}
- case NODE_MATH_ATAN: {
+ case NODE_MATH_ARCTANGENT: {
*out = atan(in0);
break;
}
- case NODE_MATH_POW: {
+ case NODE_MATH_POWER: {
/* Only raise negative numbers by full integers */
if (in0 >= 0) {
out[0] = pow(in0, in1);
@@ -114,7 +114,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
break;
}
- case NODE_MATH_LOG: {
+ case NODE_MATH_LOGARITHM: {
/* Don't want any imaginary numbers... */
if (in0 > 0 && in1 > 0) {
*out = log(in0) / log(in1);
@@ -124,7 +124,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
break;
}
- case NODE_MATH_MIN: {
+ case NODE_MATH_MINIMUM: {
if (in0 < in1) {
*out = in0;
}
@@ -133,7 +133,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
break;
}
- case NODE_MATH_MAX: {
+ case NODE_MATH_MAXIMUM: {
if (in0 > in1) {
*out = in0;
}
@@ -147,7 +147,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
- case NODE_MATH_LESS: {
+ case NODE_MATH_LESS_THAN: {
if (in0 < in1) {
*out = 1.0f;
}
@@ -157,7 +157,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
- case NODE_MATH_GREATER: {
+ case NODE_MATH_GREATER_THAN: {
if (in0 > in1) {
*out = 1.0f;
}
@@ -167,7 +167,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
- case NODE_MATH_MOD: {
+ case NODE_MATH_MODULO: {
if (in1 == 0.0f) {
*out = 0.0f;
}
@@ -177,12 +177,12 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
- case NODE_MATH_ABS: {
+ case NODE_MATH_ABSOLUTE: {
*out = fabsf(in0);
break;
}
- case NODE_MATH_ATAN2: {
+ case NODE_MATH_ARCTAN2: {
*out = atan2(in0, in1);
break;
}
@@ -197,7 +197,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
- case NODE_MATH_FRACT: {
+ case NODE_MATH_FRACTION: {
*out = in0 - floorf(in0);
break;
}