Cycles: add Object Info node, with outputs object location, object/material

pass index, and a random number unique to the instance of the object.

This can be useful to give some variation to a single material assigned to
multiple instances, either manually controlled through the object index, based
on the object location, or randomized for each instance. 

http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Nodes/More#Object_Info
This commit is contained in:
Brecht Van Lommel 2012-05-21 12:52:28 +00:00
parent ea11bc980a
commit c3e1fce775
20 changed files with 1778 additions and 1575 deletions

@ -245,6 +245,7 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob,
/* object sync */
if(object_updated || (object->mesh && object->mesh->need_update)) {
object->name = b_ob.name().c_str();
object->instance_id = b_index;
object->pass_id = b_ob.pass_index();
object->tfm = tfm;
object->motion.pre = tfm;

@ -334,6 +334,10 @@ static ShaderNode *add_node(BL::BlendData b_data, ShaderGraph *graph, BL::Shader
node = new LightFalloffNode();
break;
}
case BL::ShaderNode::type_OBJECT_INFO: {
node = new ObjectInfoNode();
break;
}
case BL::ShaderNode::type_TEX_IMAGE: {
BL::ShaderNodeTexImage b_image_node(b_node);
BL::Image b_image(b_image_node.image());

@ -117,6 +117,16 @@ __device_inline void object_dir_transform(KernelGlobals *kg, ShaderData *sd, flo
#endif
}
__device_inline float3 object_location(KernelGlobals *kg, ShaderData *sd)
{
#ifdef __MOTION__
return make_float3(sd->ob_tfm.x.w, sd->ob_tfm.y.w, sd->ob_tfm.z.w);
#else
Transform tfm = object_fetch_transform(kg, sd->object, 0.0f, OBJECT_TRANSFORM);
return make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
#endif
}
__device_inline float object_surface_area(KernelGlobals *kg, int object)
{
int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
@ -134,5 +144,20 @@ __device_inline float object_pass_id(KernelGlobals *kg, int object)
return f.y;
}
__device_inline float object_random_number(KernelGlobals *kg, int object)
{
if(object == ~0)
return 0.0f;
int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
float4 f = kernel_tex_fetch(__objects, offset);
return f.z;
}
__device int shader_pass_id(KernelGlobals *kg, ShaderData *sd)
{
return kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2 + 1);
}
CCL_NAMESPACE_END

@ -679,11 +679,6 @@ __device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect)
}
#endif
__device int shader_pass_id(KernelGlobals *kg, ShaderData *sd)
{
return kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2 + 1);
}
/* Free ShaderData */
__device void shader_release(KernelGlobals *kg, ShaderData *sd)

@ -266,6 +266,9 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT
case NODE_LIGHT_PATH:
svm_node_light_path(sd, stack, node.y, node.z, path_flag);
break;
case NODE_OBJECT_INFO:
svm_node_object_info(kg, sd, stack, node.y, node.z);
break;
#endif
case NODE_CONVERT:
svm_node_convert(sd, stack, node.y, node.z, node.w);

@ -74,5 +74,25 @@ __device void svm_node_geometry_bump_dy(ShaderData *sd, float *stack, uint type,
#endif
}
/* Object Info */
__device void svm_node_object_info(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset)
{
float data;
switch(type) {
case NODE_INFO_OB_LOCATION: {
stack_store_float3(stack, out_offset, object_location(kg, sd));
return;
}
case NODE_INFO_OB_INDEX: data = object_pass_id(kg, sd->object); break;
case NODE_INFO_MAT_INDEX: data = shader_pass_id(kg, sd); break;
case NODE_INFO_OB_RANDOM: data = object_random_number(kg, sd->object); break;
default: data = 0.0f; break;
}
stack_store_float(stack, out_offset, data);
}
CCL_NAMESPACE_END

@ -92,7 +92,8 @@ typedef enum NodeType {
NODE_RGB_RAMP = 5900,
NODE_RGB_CURVES = 6000,
NODE_MIN_MAX = 6100,
NODE_LIGHT_FALLOFF = 6200
NODE_LIGHT_FALLOFF = 6200,
NODE_OBJECT_INFO = 6300
} NodeType;
typedef enum NodeAttributeType {
@ -109,6 +110,13 @@ typedef enum NodeGeometry {
NODE_GEOM_uv
} NodeGeometry;
typedef enum NodeObjectInfo {
NODE_INFO_OB_LOCATION,
NODE_INFO_OB_INDEX,
NODE_INFO_MAT_INDEX,
NODE_INFO_OB_RANDOM
} NodeObjectInfo;
typedef enum NodeLightPath {
NODE_LP_camera = 0,
NODE_LP_shadow,

@ -1699,7 +1699,7 @@ void LightPathNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_light_path");
}
/* Light Path */
/* Light Falloff */
LightFalloffNode::LightFalloffNode()
: ShaderNode("light_path")
@ -1746,6 +1746,49 @@ void LightFalloffNode::compile(OSLCompiler& compiler)
compiler.add(this, "node_light_falloff");
}
/* Object Info */
ObjectInfoNode::ObjectInfoNode()
: ShaderNode("object_info")
{
add_output("Location", SHADER_SOCKET_VECTOR);
add_output("Object Index", SHADER_SOCKET_FLOAT);
add_output("Material Index", SHADER_SOCKET_FLOAT);
add_output("Random", SHADER_SOCKET_FLOAT);
}
void ObjectInfoNode::compile(SVMCompiler& compiler)
{
ShaderOutput *out = output("Location");
if(!out->links.empty()) {
compiler.stack_assign(out);
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_LOCATION, out->stack_offset);
}
out = output("Object Index");
if(!out->links.empty()) {
compiler.stack_assign(out);
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_INDEX, out->stack_offset);
}
out = output("Material Index");
if(!out->links.empty()) {
compiler.stack_assign(out);
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_MAT_INDEX, out->stack_offset);
}
out = output("Random");
if(!out->links.empty()) {
compiler.stack_assign(out);
compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_RANDOM, out->stack_offset);
}
}
void ObjectInfoNode::compile(OSLCompiler& compiler)
{
compiler.add(this, "node_object_info");
}
/* Value */
ValueNode::ValueNode()

@ -285,6 +285,11 @@ public:
SHADER_NODE_CLASS(LightFalloffNode)
};
class ObjectInfoNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ObjectInfoNode)
};
class ValueNode : public ShaderNode {
public:
SHADER_NODE_CLASS(ValueNode)

@ -23,6 +23,7 @@
#include "scene.h"
#include "util_foreach.h"
#include "util_hash.h"
#include "util_map.h"
#include "util_progress.h"
@ -36,6 +37,7 @@ Object::Object()
mesh = NULL;
tfm = transform_identity();
visibility = ~0;
instance_id = 0;
pass_id = 0;
bounds = BoundBox::empty;
motion.pre = transform_identity();
@ -164,6 +166,9 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
float surface_area = 0.0f;
float pass_id = ob->pass_id;
uint ob_hash = hash_int_2d(hash_string(ob->name.c_str()), ob->instance_id);
float random_number = (float)ob_hash * (1.0f/(float)0xFFFFFFFF);
if(transform_uniform_scale(tfm, uniform_scale)) {
map<Mesh*, float>::iterator it = surface_area_map.find(mesh);
@ -198,7 +203,7 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene
memcpy(&objects[offset], &tfm, sizeof(float4)*3);
memcpy(&objects[offset+3], &itfm, sizeof(float4)*3);
objects[offset+6] = make_float4(surface_area, pass_id, 0.0f, 0.0f);
objects[offset+6] = make_float4(surface_area, pass_id, random_number, 0.0f);
if(need_motion == Scene::MOTION_PASS) {
/* motion transformations, is world/object space depending if mesh

@ -41,6 +41,7 @@ public:
Transform tfm;
BoundBox bounds;
ustring name;
int instance_id;
int pass_id;
vector<ParamValue> attributes;
uint visibility;

@ -19,13 +19,15 @@
#ifndef __UTIL_HASH_H__
#define __UTIL_HASH_H__
#include "util_types.h"
CCL_NAMESPACE_BEGIN
static inline unsigned int hash_int_2d(unsigned int kx, unsigned int ky)
static inline uint hash_int_2d(uint kx, uint ky)
{
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
unsigned int a, b, c;
uint a, b, c;
a = b = c = 0xdeadbeef + (2 << 2) + 13;
a += kx;
@ -44,11 +46,21 @@ static inline unsigned int hash_int_2d(unsigned int kx, unsigned int ky)
#undef rot
}
static inline unsigned int hash_int(unsigned int k)
static inline uint hash_int(uint k)
{
return hash_int_2d(k, 0);
}
static inline uint hash_string(const char *str)
{
uint i = 0, c;
while ((c = *str++))
i = i * 37 + c;
return i;
}
CCL_NAMESPACE_END
#endif /* __UTIL_HASH_H__ */

@ -516,6 +516,7 @@ struct ShadeResult;
#define SH_NODE_TEX_CHECKER 164
#define SH_NODE_BRIGHTCONTRAST 165
#define SH_NODE_LIGHT_FALLOFF 166
#define SH_NODE_OBJECT_INFO 167
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1

@ -1977,6 +1977,7 @@ static void registerShaderNodes(bNodeTreeType *ttype)
register_node_type_sh_geometry(ttype);
register_node_type_sh_light_path(ttype);
register_node_type_sh_light_falloff(ttype);
register_node_type_sh_object_info(ttype);
register_node_type_sh_fresnel(ttype);
register_node_type_sh_layer_weight(ttype);
register_node_type_sh_tex_coord(ttype);

@ -2206,6 +2206,15 @@ void node_light_falloff(float strength, float tsmooth, out float quadratic, out
constant = strength;
}
void node_object_info(out vec3 location, out float object_index, out float material_index, out float random)
{
location = vec3(0.0);
object_index = 0.0;
material_index = 0.0;
random = 0.0;
}
/* output */
void node_output_material(vec4 surface, vec4 volume, float displacement, out vec4 result)

File diff suppressed because it is too large Load Diff

@ -77,8 +77,9 @@ DefNode( ShaderNode, SH_NODE_VOLUME_TRANSPARENT, 0, "VO
DefNode( ShaderNode, SH_NODE_VOLUME_ISOTROPIC, 0, "VOLUME_ISOTROPIC", VolumeIsotropic, "Isotropic Volume", "" )
DefNode( ShaderNode, SH_NODE_EMISSION, 0, "EMISSION", Emission, "Emission", "" )
DefNode( ShaderNode, SH_NODE_NEW_GEOMETRY, 0, "NEW_GEOMETRY", NewGeometry, "Geometry", "" )
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_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_TEX_IMAGE, def_sh_tex_image, "TEX_IMAGE", TexImage, "Image Texture", "" )
DefNode( ShaderNode, SH_NODE_TEX_ENVIRONMENT, def_sh_tex_environment, "TEX_ENVIRONMENT", TexEnvironment, "Environment Texture","" )
DefNode( ShaderNode, SH_NODE_TEX_SKY, def_sh_tex_sky, "TEX_SKY", TexSky, "Sky Texture", "" )

@ -158,6 +158,7 @@ set(SRC
shader/nodes/node_shader_volume_isotropic.c
shader/nodes/node_shader_light_path.c
shader/nodes/node_shader_light_falloff.c
shader/nodes/node_shader_object_info.c
shader/nodes/node_shader_mix_shader.c
shader/nodes/node_shader_add_shader.c
shader/nodes/node_shader_output_lamp.c

@ -74,6 +74,7 @@ void register_node_type_sh_attribute(struct bNodeTreeType *ttype);
void register_node_type_sh_geometry(struct bNodeTreeType *ttype);
void register_node_type_sh_light_path(struct bNodeTreeType *ttype);
void register_node_type_sh_light_falloff(struct bNodeTreeType *ttype);
void register_node_type_sh_object_info(struct bNodeTreeType *ttype);
void register_node_type_sh_fresnel(struct bNodeTreeType *ttype);
void register_node_type_sh_layer_weight(struct bNodeTreeType *ttype);
void register_node_type_sh_tex_coord(struct bNodeTreeType *ttype);

@ -0,0 +1,61 @@
/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* 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.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#include "../node_shader_util.h"
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_object_info_out[]= {
{ SOCK_VECTOR, 0, "Location", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, "Object Index", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, "Material Index", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, "Random", 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
};
static int node_shader_gpu_object_info(GPUMaterial *mat, bNode *UNUSED(node), GPUNodeStack *in, GPUNodeStack *out)
{
return GPU_stack_link(mat, "node_object_info", in, out);
}
/* node type definition */
void register_node_type_sh_object_info(bNodeTreeType *ttype)
{
static bNodeType ntype;
node_type_base(ttype, &ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0);
node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, NULL, sh_node_object_info_out);
node_type_size(&ntype, 150, 60, 200);
node_type_init(&ntype, NULL);
node_type_storage(&ntype, "", NULL, NULL);
node_type_exec(&ntype, NULL);
node_type_gpu(&ntype, node_shader_gpu_object_info);
nodeRegisterType(ttype, &ntype);
}