diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 94a55738f2b..c80adba1795 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -152,9 +152,7 @@ enum PathTraceDimension { PRNG_BOUNCE_NUM = 8 }; -/* these flag values correspond exactly to OSL defaults, so be careful not to - * change this, or if you do, set the "raytypes" shading system attribute with - * your own new ray types and bitflag values. +/* these flags values correspond to raytypes in osl.cpp, so keep them in sync! * * for ray visibility tests in BVH traversal, the upper 20 bits are used for * layer visibility tests. */ diff --git a/intern/cycles/kernel/osl/nodes/CMakeLists.txt b/intern/cycles/kernel/osl/nodes/CMakeLists.txt index 2c459fd714b..da5441f11e0 100644 --- a/intern/cycles/kernel/osl/nodes/CMakeLists.txt +++ b/intern/cycles/kernel/osl/nodes/CMakeLists.txt @@ -48,6 +48,7 @@ set(SRC_OSL node_particle_info.osl node_rgb_ramp.osl node_separate_rgb.osl + node_set_normal.osl node_sky_texture.osl node_texture_coordinate.osl node_translucent_bsdf.osl diff --git a/intern/cycles/kernel/osl/nodes/node_bump.osl b/intern/cycles/kernel/osl/nodes/node_bump.osl index dbc554e0a72..24db1b24458 100644 --- a/intern/cycles/kernel/osl/nodes/node_bump.osl +++ b/intern/cycles/kernel/osl/nodes/node_bump.osl @@ -22,25 +22,28 @@ * Morten S. Mikkelsen, 2010 */ surface node_bump( + normal NormalIn = N, + float Strength = 0.0, float SampleCenter = 0.0, float SampleX = 0.0, float SampleY = 0.0, output normal Normal = N) { - float dx = SampleX - SampleCenter; - float dy = SampleY - SampleCenter; - + /* get surface tangents from normal */ vector dPdx = Dx(P); vector dPdy = Dy(P); - vector Rx = cross(dPdy, N); - vector Ry = cross(N, dPdx); + vector Rx = cross(dPdy, NormalIn); + vector Ry = cross(NormalIn, dPdx); + /* compute surface gradient and determinant */ float det = dot(dPdx, Rx); - vector surfgrad = dx * Rx + dy * Ry; + vector surfgrad = (SampleX - SampleCenter) * Rx + (SampleY - SampleCenter) * Ry; - surfgrad *= 0.1; /* todo: remove this factor */ + surfgrad *= Strength; + float absdet = fabs(det); - Normal = normalize(abs(det) * N - sign(det) * surfgrad); + /* compute and output perturbed normal */ + Normal = normalize(absdet * NormalIn - sign(det) * surfgrad); } diff --git a/intern/cycles/kernel/osl/nodes/node_image_texture.osl b/intern/cycles/kernel/osl/nodes/node_image_texture.osl index e005f1f4245..2ca7e682a35 100644 --- a/intern/cycles/kernel/osl/nodes/node_image_texture.osl +++ b/intern/cycles/kernel/osl/nodes/node_image_texture.osl @@ -19,16 +19,102 @@ #include "stdosl.h" #include "node_color.h" +color image_texture_lookup(string filename, string color_space, float u, float v, output float Alpha) +{ + color rgb = (color)texture(filename, u, 1.0 - v, "wrap", "periodic", "alpha", Alpha); + + if(color_space == "sRGB") + rgb = color_srgb_to_scene_linear(rgb); + + return rgb; +} + shader node_image_texture( point Vector = P, string filename = "", string color_space = "sRGB", + string projection = "Flat", + float projection_blend = 0.0, output color Color = color(0.0, 0.0, 0.0), output float Alpha = 1.0) { - Color = (color)texture(filename, Vector[0], 1.0 - Vector[1], "wrap", "periodic", "alpha", Alpha); + if(projection == "Flat") { + Color = image_texture_lookup(filename, color_space, Vector[0], Vector[1], Alpha); + } + else if(projection == "Box") { + /* object space normal */ + vector Nob = transform("world", "object", N); - if (color_space == "sRGB") - Color = color_srgb_to_scene_linear(Color); + /* project from direction vector to barycentric coordinates in triangles */ + Nob = vector(fabs(Nob[0]), fabs(Nob[1]), fabs(Nob[2])); + Nob /= (Nob[0] + Nob[1] + Nob[2]); + + /* basic idea is to think of this as a triangle, each corner representing + * one of the 3 faces of the cube. in the corners we have single textures, + * in between we blend between two textures, and in the middle we a blend + * between three textures. + * + * the Nxyz values are the barycentric coordinates in an equilateral + * triangle, which in case of blending, in the middle has a smaller + * equilateral triangle where 3 textures blend. this divides things into + * 7 zones, with an if() test for each zone */ + + vector weight = vector(0.0, 0.0, 0.0); + float blend = projection_blend; + float limit = 0.5*(1.0 + blend); + + /* first test for corners with single texture */ + if(Nob[0] > limit*(Nob[0] + Nob[1]) && Nob[0] > limit*(Nob[0] + Nob[2])) { + weight[0] = 1.0; + } + else if(Nob[1] > limit*(Nob[0] + Nob[1]) && Nob[1] > limit*(Nob[1] + Nob[2])) { + weight[1] = 1.0; + } + else if(Nob[2] > limit*(Nob[0] + Nob[2]) && Nob[2] > limit*(Nob[1] + Nob[2])) { + weight[2] = 1.0; + } + else if(blend > 0.0) { + /* in case of blending, test for mixes between two textures */ + if(Nob[2] < (1.0 - limit)*(Nob[1] + Nob[0])) { + weight[0] = Nob[0]/(Nob[0] + Nob[1]); + weight[0] = clamp((weight[0] - 0.5*(1.0 - blend))/blend, 0.0, 1.0); + weight[1] = 1.0 - weight[0]; + } + else if(Nob[0] < (1.0 - limit)*(Nob[1] + Nob[2])) { + weight[1] = Nob[1]/(Nob[1] + Nob[2]); + weight[1] = clamp((weight[1] - 0.5*(1.0 - blend))/blend, 0.0, 1.0); + weight[2] = 1.0 - weight[1]; + } + else if(Nob[1] < (1.0 - limit)*(Nob[0] + Nob[2])) { + weight[0] = Nob[0]/(Nob[0] + Nob[2]); + weight[0] = clamp((weight[0] - 0.5*(1.0 - blend))/blend, 0.0, 1.0); + weight[2] = 1.0 - weight[0]; + } + else { + /* last case, we have a mix between three */ + weight[0] = ((2.0 - limit)*Nob[0] + (limit - 1.0))/(2.0*limit - 1.0); + weight[1] = ((2.0 - limit)*Nob[1] + (limit - 1.0))/(2.0*limit - 1.0); + weight[2] = ((2.0 - limit)*Nob[2] + (limit - 1.0))/(2.0*limit - 1.0); + } + } + + Color = color(0.0, 0.0, 0.0); + Alpha = 0.0; + + float tmp_alpha; + + if(weight[0] > 0.0) { + Color += weight[0]*image_texture_lookup(filename, color_space, Vector[1], Vector[2], tmp_alpha); + Alpha += weight[0]*tmp_alpha; + } + if(weight[1] > 0.0) { + Color += weight[1]*image_texture_lookup(filename, color_space, Vector[0], Vector[2], tmp_alpha); + Alpha += weight[1]*tmp_alpha; + } + if(weight[2] > 0.0) { + Color += weight[2]*image_texture_lookup(filename, color_space, Vector[1], Vector[0], tmp_alpha); + Alpha += weight[2]*tmp_alpha; + } + } } diff --git a/intern/cycles/kernel/osl/nodes/node_set_normal.osl b/intern/cycles/kernel/osl/nodes/node_set_normal.osl new file mode 100644 index 00000000000..27a4b2f5b8b --- /dev/null +++ b/intern/cycles/kernel/osl/nodes/node_set_normal.osl @@ -0,0 +1,28 @@ +/* + * Copyright 2012, Blender Foundation. + * + * 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. + */ + +#include "stdosl.h" + +surface node_set_normal( + normal Direction = N, + output normal Normal = N) +{ + N = Direction; + Normal = Direction; +} + diff --git a/intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl b/intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl index 883135d2a43..405ed118c2b 100644 --- a/intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl +++ b/intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl @@ -19,8 +19,9 @@ #include "stdosl.h" shader node_texture_coordinate( - normal Normal = N, + normal NormalIn = N, int is_background = 0, + int from_dupli = 0, string bump_offset = "center", output point Generated = point(0.0, 0.0, 0.0), @@ -28,6 +29,7 @@ shader node_texture_coordinate( output point Object = point(0.0, 0.0, 0.0), output point Camera = point(0.0, 0.0, 0.0), output point Window = point(0.0, 0.0, 0.0), + output normal Normal = normal(0.0, 0.0, 0.0), output point Reflection = point(0.0, 0.0, 0.0)) { if (is_background) { @@ -37,27 +39,40 @@ shader node_texture_coordinate( point Pcam = transform("camera", "world", point(0, 0, 0)); Camera = transform("camera", P + Pcam); Window = transform("NDC", P + Pcam); + Normal = NormalIn; Reflection = I; } else { - getattribute("std::generated", Generated); - getattribute("std::uv", UV); + if (from_dupli) { + getattribute("std::dupli_generated", Generated); + getattribute("std::dupli_uv", UV); + } + else { + getattribute("std::generated", Generated); + getattribute("std::uv", UV); + } + Object = transform("object", P); Camera = transform("camera", P); Window = transform("NDC", P); - Reflection = reflect(I, Normal); + Normal = transform("world", "object", NormalIn); + Reflection = reflect(I, NormalIn); } if (bump_offset == "dx") { - Generated += Dx(Generated); - UV += Dx(UV); + if (!from_dupli) { + Generated += Dx(Generated); + UV += Dx(UV); + } Object += Dx(Object); Camera += Dx(Camera); Window += Dx(Window); } else if (bump_offset == "dy") { - Generated += Dy(Generated); - UV += Dy(UV); + if (!from_dupli) { + Generated += Dy(Generated); + UV += Dy(UV); + } Object += Dy(Object); Camera += Dy(Camera); Window += Dy(Window); diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 83574c91d31..7c415e22012 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -287,16 +287,26 @@ static void set_attribute_float3(float3 f[3], TypeDesc type, bool derivatives, v if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) { - float3 *fval = (float3 *)val; - fval[0] = f[0]; + float *fval = (float *)val; + + fval[0] = f[0].x; + fval[1] = f[0].y; + fval[2] = f[0].z; + if (derivatives) { - fval[1] = f[1]; - fval[2] = f[2]; + 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; } } else { float *fval = (float *)val; fval[0] = average(f[0]); + if (derivatives) { fval[1] = average(f[1]); fval[2] = average(f[2]); @@ -309,16 +319,25 @@ static void set_attribute_float(float f[3], TypeDesc type, bool derivatives, voi if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) { - float3 *fval = (float3 *)val; - fval[0] = make_float3(f[0], f[0], f[0]); + float *fval = (float *)val; + fval[0] = f[0]; + fval[1] = f[1]; + fval[2] = f[2]; + if (derivatives) { - fval[1] = make_float3(f[1], f[2], f[1]); - fval[2] = make_float3(f[2], f[2], f[2]); + fval[3] = f[1]; + fval[4] = f[1]; + fval[5] = f[1]; + + fval[6] = f[2]; + fval[7] = f[2]; + fval[8] = f[2]; } } else { float *fval = (float *)val; fval[0] = f[0]; + if (derivatives) { fval[1] = f[1]; fval[2] = f[2]; @@ -377,6 +396,20 @@ static bool get_object_standard_attribute(KernelGlobals *kg, ShaderData *sd, ust set_attribute_float(fval, type, derivatives, val); return true; } + else if (name == "std::dupli_generated") { + float3 fval[3]; + fval[0] = object_dupli_generated(kg, sd->object); + fval[1] = fval[2] = make_float3(0.0, 0.0, 0.0); /* derivates set to 0 */ + set_attribute_float3(fval, type, derivatives, val); + return true; + } + else if (name == "std::dupli_uv") { + float3 fval[3]; + fval[0] = object_dupli_uv(kg, sd->object); + fval[1] = fval[2] = make_float3(0.0, 0.0, 0.0); /* derivates set to 0 */ + set_attribute_float3(fval, type, derivatives, val); + return true; + } else if (name == "std::material_index") { float fval[3]; fval[0] = shader_pass_id(kg, sd); diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index 662419418e3..9877856fec2 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -265,7 +265,7 @@ __device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float *s * between three textures. * * the Nxyz values are the barycentric coordinates in an equilateral - * triangle, which in case of blending in the middle has a smaller + * triangle, which in case of blending, in the middle has a smaller * equilateral triangle where 3 textures blend. this divides things into * 7 zones, with an if() test for each zone */ diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 76267e9d014..da0dbc12740 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -225,6 +225,8 @@ void ImageTextureNode::compile(OSLCompiler& compiler) compiler.parameter("color_space", "Linear"); else compiler.parameter("color_space", "sRGB"); + compiler.parameter("projection", projection); + compiler.parameter("projection_blend", projection_blend); compiler.add(this, "node_image_texture"); } @@ -1701,7 +1703,7 @@ void GeometryNode::compile(OSLCompiler& compiler) TextureCoordinateNode::TextureCoordinateNode() : ShaderNode("texture_coordinate") { - add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); add_output("Generated", SHADER_SOCKET_POINT); add_output("Normal", SHADER_SOCKET_NORMAL); add_output("UV", SHADER_SOCKET_POINT); @@ -1823,6 +1825,8 @@ void TextureCoordinateNode::compile(OSLCompiler& compiler) if(compiler.background) compiler.parameter("is_background", true); + + compiler.parameter("from_dupli", from_dupli); compiler.add(this, "node_texture_coordinate"); } @@ -2770,7 +2774,7 @@ BumpNode::BumpNode() { /* this input is used by the user, but after graph transform it is no longer * used and moved to sampler center/x/y instead */ - add_input("Height", SHADER_SOCKET_NORMAL); + add_input("Height", SHADER_SOCKET_FLOAT); add_input("SampleCenter", SHADER_SOCKET_FLOAT); add_input("SampleX", SHADER_SOCKET_FLOAT); @@ -2909,7 +2913,7 @@ void SetNormalNode::compile(SVMCompiler& compiler) void SetNormalNode::compile(OSLCompiler& compiler) { - compiler.add(this, "set_normal"); + compiler.add(this, "node_set_normal"); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index 21e6c7749b8..638bfa8634e 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -59,6 +59,22 @@ OSLShaderManager::OSLShaderManager() //ss->attribute("statistics:level", 1); ss->attribute("searchpath:shader", path_get("shader").c_str()); + /* our own ray types */ + static const char *raytypes[] = { + "camera", /* PATH_RAY_CAMERA */ + "reflection", /* PATH_RAY_REFLECT */ + "refraction", /* PATH_RAY_TRANSMIT */ + "diffuse", /* PATH_RAY_DIFFUSE */ + "glossy", /* PATH_RAY_GLOSSY */ + "singular", /* PATH_RAY_SINGULAR */ + "transparent", /* PATH_RAY_TRANSPARENT */ + "shadow", /* PATH_RAY_SHADOW_OPAQUE */ + "shadow", /* PATH_RAY_SHADOW_TRANSPARENT */ + }; + + const int nraytypes = sizeof(raytypes)/sizeof(raytypes[0]); + ss->attribute("raytypes", TypeDesc(TypeDesc::STRING, nraytypes), raytypes); + OSLShader::register_closures(ss); } @@ -209,6 +225,10 @@ bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input) if(strcmp(input->name, "Normal") == 0) return true; } + else if(node->name == ustring("bump")) { + if(strcmp(input->name, "Height") == 0) + return true; + } else if(current_type == SHADER_TYPE_DISPLACEMENT && input->link && input->link->parent->name == ustring("bump")) return true;