Cycles OSL: light path, texture coordinate, bump and blended box mapping now up

to date and working.
This commit is contained in:
Brecht Van Lommel 2012-10-20 15:09:36 +00:00
parent e287c97fea
commit 73b79a6763
10 changed files with 222 additions and 34 deletions

@ -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. */

@ -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

@ -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);
}

@ -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;
}
}
}

@ -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;
}

@ -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);

@ -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);

@ -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 */

@ -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

@ -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;