diff options
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; } |