diff options
29 files changed, 686 insertions, 99 deletions
diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 29a1408d85d..4dba8ffbe0e 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_uint2_to_float(num_curves, 0)); } mesh->add_curve(num_keys, CData->psys_shader[sys]); diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 7ccf8226e5b..ab47da9c1a2 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) @@ -490,7 +490,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 047cc82dbfc..9a798a4f979 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_uint2(view_index * 0xdeadbeef, 0)); scene->integrator->tag_update(scene); } diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 322a1771786..fdefe2140bd 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -844,6 +844,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 *white_noise_node = new WhiteNoiseTextureNode(); + white_noise_node->dimensions = b_tex_white_noise_node.dimensions(); + node = white_noise_node; + } else if (b_node.is_a(&RNA_ShaderNodeNormalMap)) { BL::ShaderNodeNormalMap b_normal_map_node(b_node); NormalMapNode *nmap = new NormalMapNode(); diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index bac571b02ce..aec21887088 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((int)(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 ab05d6ee1e9..48439a8b68f 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -221,6 +221,7 @@ set(SRC_SVM_HEADERS svm/svm_voronoi.h svm/svm_voxel.h svm/svm_wave.h + svm/svm_white_noise.h ) set(SRC_GEOM_HEADERS 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/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 316d24b0954..3850d0fe94b 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -697,7 +697,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_uint2_to_float(particle_index(kg, particle_id), 0); return set_attribute_float(f, type, derivatives, val); } diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index 63cef6e841b..c50bffe27b2 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -85,6 +85,7 @@ set(SRC_OSL node_wavelength.osl node_blackbody.osl node_wave_texture.osl + node_white_noise_texture.osl node_wireframe.osl node_hair_bsdf.osl node_principled_hair_bsdf.osl 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..f026fb4ab39 --- /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 = point(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/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 0d731d62e94..8f8451b364d 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -194,6 +194,7 @@ CCL_NAMESPACE_END #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" #ifdef __SHADER_RAYTRACE__ # include "kernel/svm/svm_ao.h" @@ -432,6 +433,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: diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h index a9104643299..4abe0831858 100644 --- a/intern/cycles/kernel/svm/svm_geometry.h +++ b/intern/cycles/kernel/svm/svm_geometry.h @@ -149,7 +149,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_uint2_to_float(particle_index(kg, particle_id), 0); stack_store_float(stack, out_offset, random); break; } diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h index 322579ccfe3..0bf3dfda4df 100644 --- a/intern/cycles/kernel/svm/svm_noise.h +++ b/intern/cycles/kernel/svm/svm_noise.h @@ -41,42 +41,6 @@ ccl_device_inline ssei quick_floor_sse(const ssef &x) } #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) { @@ -236,17 +200,19 @@ ccl_device_noinline float perlin(float x, float y, float z) 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))), + grad(hash_uint3(X, Y, Z), fx, fy, fz), + grad(hash_uint3(X + 1, Y, Z), fx - 1.0f, fy, fz)), + nerp(u, + grad(hash_uint3(X, Y + 1, Z), fx, fy - 1.0f, fz), + grad(hash_uint3(X + 1, Y + 1, Z), fx - 1.0f, fy - 1.0f, fz))), nerp(v, nerp(u, - grad(hash(X, Y, Z + 1), fx, fy, fz - 1.0f), - grad(hash(X + 1, Y, Z + 1), fx - 1.0f, fy, fz - 1.0f)), + grad(hash_uint3(X, Y, Z + 1), fx, fy, fz - 1.0f), + grad(hash_uint3(X + 1, Y, Z + 1), fx - 1.0f, fy, fz - 1.0f)), nerp(u, - grad(hash(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)))); + grad(hash_uint3(X, Y + 1, Z + 1), fx, fy - 1.0f, fz - 1.0f), + grad(hash_uint3(X + 1, Y + 1, Z + 1), fx - 1.0f, fy - 1.0f, fz - 1.0f)))); float r = scale3(result); /* can happen for big coordinates, things even out to 0.0 then anyway */ @@ -312,16 +278,16 @@ ccl_device float snoise(float3 p) ccl_device float cellnoise(float3 p) { int3 ip = quick_floor_to_int3(p); - return bits_to_01(hash(ip.x, ip.y, ip.z)); + return hash_uint3_to_float(ip.x, ip.y, ip.z); } ccl_device float3 cellnoise3(float3 p) { 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)); + float r = hash_uint3_to_float(ip.x, ip.y, ip.z); + float g = hash_uint3_to_float(ip.y, ip.x, ip.z); + float b = hash_uint3_to_float(ip.y, ip.z, ip.x); return make_float3(r, g, b); #else ssei ip_yxz = shuffle<1, 0, 2, 3>(ssei(ip.m128)); diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index 884ad76a9b7..6f412074125 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -140,6 +140,7 @@ typedef enum ShaderNodeType { NODE_IES, NODE_MAP_RANGE, NODE_CLAMP, + NODE_TEX_WHITE_NOISE, } ShaderNodeType; typedef enum NodeAttributeType { 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..77cbb88a8e2 --- /dev/null +++ b/intern/cycles/kernel/svm/svm_white_noise.h @@ -0,0 +1,53 @@ +/* + * 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 inputs_stack_offsets, + uint value_stack_offset, + int *offset) +{ + uint vector_stack_offset, w_stack_offset; + decode_node_uchar4(inputs_stack_offsets, &vector_stack_offset, &w_stack_offset, NULL, NULL); + + float3 vector = stack_load_float3(stack, vector_stack_offset); + float w = stack_load_float(stack, w_stack_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, value_stack_offset, value); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index 76258a292e8..b41b0b7b260 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_uint2(seed, 0); kintegrator->use_ambient_occlusion = ((Pass::contains(scene->film->passes, PASS_AO)) || dscene->data.background.ao_factor != 0.0f); diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 8c8bb559c30..6435894d41a 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1110,6 +1110,53 @@ 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"); + + int vector_stack_offset = compiler.stack_assign(vector_in); + int w_stack_offset = compiler.stack_assign(w_in); + int value_stack_offset = compiler.stack_assign(value_out); + + compiler.add_node(NODE_TEX_WHITE_NOISE, + dimensions, + compiler.encode_uchar4(vector_stack_offset, w_stack_offset), + value_stack_offset); +} + +void WhiteNoiseTextureNode::compile(OSLCompiler &compiler) +{ + compiler.parameter(this, "dimensions"); + compiler.add(this, "node_white_noise_texture"); +} + /* Musgrave Texture */ NODE_DEFINE(MusgraveTextureNode) diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 417623c7562..9c4e643e727 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -370,6 +370,19 @@ class IESLightNode : public TextureNode { void get_slot(); }; +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 MappingNode : public ShaderNode { public: SHADER_NODE_CLASS(MappingNode) diff --git a/intern/cycles/util/util_hash.h b/intern/cycles/util/util_hash.h index 785482967db..2b1f26de03d 100644 --- a/intern/cycles/util/util_hash.h +++ b/intern/cycles/util/util_hash.h @@ -21,39 +21,196 @@ 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 + +/* 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 uint hash_int(uint k) +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 hash_int_2d(k, 0); + 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 +225,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/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index c6e83a646e5..c0ef3f8b151 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -237,6 +237,7 @@ shader_node_categories = [ NodeItem("ShaderNodeTexBrick"), NodeItem("ShaderNodeTexPointDensity"), NodeItem("ShaderNodeTexIES"), + NodeItem("ShaderNodeTexWhiteNoise"), ]), ShaderNodeCategory("SH_NEW_OP_COLOR", "Color", items=[ NodeItem("ShaderNodeMixRGB"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 1b7debe4496..6852f451b9d 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -978,6 +978,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, #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 /* 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 7e455ba742a..11a52bf53a9 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3933,6 +3933,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/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 4201fe7c289..cc2fb6e1c2a 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -1186,6 +1186,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) { @@ -1330,6 +1335,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; } } diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 1817efd35d2..df8f9d9457c 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1166,9 +1166,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; \ @@ -1186,9 +1211,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; @@ -1196,15 +1246,157 @@ 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)); } +uint hash_int3(int kx, int ky, int kz) +{ + return hash_uint3(uint(kx), uint(ky), uint(kz)); +} + +uint hash_int4(int kx, int ky, int kz, int kw) +{ + return hash_uint4(uint(kx), uint(ky), uint(kz), uint(kw)); +} + +/* 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)); +} + +float hash_vec2_to_float(vec2 k) +{ + 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]. */ + +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)); +} + +/* Cell Noise */ + float bits_to_01(uint bits) { return (float(bits) / 4294967295.0); @@ -1216,7 +1408,7 @@ float cellnoise(vec3 p) int iy = quick_floor(p.y); int iz = quick_floor(p.z); - return bits_to_01(hash(uint(ix), uint(iy), uint(iz))); + return hash_uint3_to_float(uint(ix), uint(iy), uint(iz)); } vec3 cellnoise_color(vec3 p) @@ -2901,22 +3093,24 @@ float noise_perlin(float x, float y, float z) float noise_u[2], noise_v[2]; - 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)); + noise_u[0] = noise_nerp(u, + noise_grad(hash_int3(X, Y, Z), fx, fy, fz), + noise_grad(hash_int3(X + 1, Y, Z), fx - 1.0, fy, fz)); 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)); + noise_grad(hash_int3(X, Y + 1, Z), fx, fy - 1.0, fz), + noise_grad(hash_int3(X + 1, Y + 1, Z), fx - 1.0, fy - 1.0, fz)); noise_v[0] = noise_nerp(v, noise_u[0], noise_u[1]); 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)); + noise_grad(hash_int3(X, Y, Z + 1), fx, fy, fz - 1.0), + noise_grad(hash_int3(X + 1, Y, Z + 1), fx - 1.0, fy, fz - 1.0)); - 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)); + noise_u[1] = noise_nerp( + u, + noise_grad(hash_int3(X, Y + 1, Z + 1), fx, fy - 1.0, fz - 1.0), + noise_grad(hash_int3(X + 1, Y + 1, Z + 1), fx - 1.0, fy - 1.0, fz - 1.0)); noise_v[1] = noise_nerp(v, noise_u[0], noise_u[1]); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index f377ae9a84f..b7a2dd9a185 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -170,6 +170,14 @@ const EnumPropertyItem rna_enum_node_vec_math_items[] = { {0, NULL, 0, NULL, NULL}, }; +const EnumPropertyItem rna_enum_node_tex_dimensions_items[] = { + {1, "1D", 0, "1D", "Use the scalar value W as input"}, + {2, "2D", 0, "2D", "Use the 2D vector (x, y) as input. The z component is ignored"}, + {3, "3D", 0, "3D", "Use the 3D vector Vector as input"}, + {4, "4D", 0, "4D", "Use the 4D vector (x, y, z, w) as input"}, + {0, NULL, 0, NULL, NULL}, +}; + const EnumPropertyItem rna_enum_node_filter_items[] = { {0, "SOFTEN", 0, "Soften", ""}, {1, "SHARPEN", 0, "Sharpen", ""}, @@ -4497,6 +4505,18 @@ 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", "The number of dimensions to evaluate the noise in"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update"); +} + static void def_sh_tex_coord(StructRNA *srna) { PropertyRNA *prop; diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 3c97bdae929..0e8248d2d34 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -200,6 +200,7 @@ 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_valToRgb.c diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index 9349a428021..71ed11a8cea 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -131,6 +131,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 c08911c1db8..877a2981a90 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -127,6 +127,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/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..c0f9a033476 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.c @@ -0,0 +1,76 @@ +/* + * 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", + }; + + return GPU_stack_link(mat, node, names[node->custom1], in, out); +} + +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); +} |