diff options
25 files changed, 460 insertions, 50 deletions
diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index 003c6c84f8f..a8c7eef89fa 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -22,6 +22,7 @@ set(SRC blender_camera.cpp blender_mesh.cpp blender_object.cpp + blender_particles.cpp blender_python.cpp blender_session.cpp blender_shader.cpp diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index cea3b0256bd..b70491a7b82 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -192,7 +192,7 @@ void BlenderSync::sync_background_light() /* Object */ -void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint layer_flag, int motion) +void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm, uint layer_flag, int motion, int particle_id) { /* light is handled separately */ if(object_is_light(b_ob)) { @@ -270,6 +270,12 @@ void BlenderSync::sync_object(BL::Object b_parent, int b_index, BL::Object b_ob, object->visibility &= ~PATH_RAY_CAMERA; } + object->particle_id = particle_id; + + /* particle sync */ + if (object_use_particles(b_ob)) + sync_particles(object, b_ob); + object->tag_update(scene); } } @@ -292,54 +298,51 @@ void BlenderSync::sync_objects(BL::SpaceView3D b_v3d, int motion) /* object loop */ BL::Scene::objects_iterator b_ob; BL::Scene b_sce = b_scene; + int particle_offset = 0; for(; b_sce; b_sce = b_sce.background_set()) { for(b_sce.objects.begin(b_ob); b_ob != b_sce.objects.end(); ++b_ob) { bool hide = (render_layer.use_viewport_visibility)? b_ob->hide(): b_ob->hide_render(); uint ob_layer = get_layer(b_ob->layers()); + hide = hide || !(ob_layer & scene_layer); + + if(!hide) { + + int num_particles = object_count_particles(*b_ob); - if(!hide && (ob_layer & scene_layer)) { if(b_ob->is_duplicator()) { + hide = true; /* duplicators hidden by default */ + /* dupli objects */ object_create_duplilist(*b_ob, b_scene); BL::Object::dupli_list_iterator b_dup; - int b_index = 0; - for(b_ob->dupli_list.begin(b_dup); b_dup != b_ob->dupli_list.end(); ++b_dup) { Transform tfm = get_transform(b_dup->matrix()); BL::Object b_dup_ob = b_dup->object(); bool dup_hide = (b_v3d)? b_dup_ob.hide(): b_dup_ob.hide_render(); - if(!(b_dup->hide() || dup_hide)) - sync_object(*b_ob, b_index, b_dup_ob, tfm, ob_layer, motion); - - b_index++; + if(!(b_dup->hide() || dup_hide)) { + sync_object(*b_ob, b_dup->index(), b_dup_ob, tfm, ob_layer, motion, b_dup->particle_index() + particle_offset); + } } object_free_duplilist(*b_ob); - - hide = true; } /* check if we should render or hide particle emitter */ BL::Object::particle_systems_iterator b_psys; - bool render_emitter = false; - - for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) { - if(b_psys->settings().use_render_emitter()) { + for(b_ob->particle_systems.begin(b_psys); b_psys != b_ob->particle_systems.end(); ++b_psys) + if(b_psys->settings().use_render_emitter()) hide = false; - render_emitter = true; - } - else if(!render_emitter) - hide = true; - } if(!hide) { /* object itself */ Transform tfm = get_transform(b_ob->matrix_world()); - sync_object(*b_ob, 0, *b_ob, tfm, ob_layer, motion); + sync_object(*b_ob, 0, *b_ob, tfm, ob_layer, motion, 0); } + + particle_offset += num_particles; } } } diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp new file mode 100644 index 00000000000..8a208cb5676 --- /dev/null +++ b/intern/cycles/blender/blender_particles.cpp @@ -0,0 +1,158 @@ +/* + * Copyright 2011, 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 "object.h" + +#include "mesh.h" +#include "blender_sync.h" +#include "blender_util.h" + +#include "util_foreach.h" + +CCL_NAMESPACE_BEGIN + +/* Utilities */ + + +/* Particles Sync */ + +bool BlenderSync::object_use_particles(BL::Object b_ob) +{ + /* Particle data is only needed for + * a) Billboard render mode if object's own material uses particle info + * b) object/group render mode if any dupli object's material uses particle info + * + * Note: Meshes have to be synced at this point! + */ + bool use_particles = false; + + BL::Object::particle_systems_iterator b_psys; + for (b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys) { + switch (b_psys->settings().render_type()) { + /* XXX not implemented yet! + * billboards/strands would become part of the mesh data (?), + * so the mesh attributes would store whether particle info is required. + */ + #if 0 + case BL::ParticleSettings::render_type_BILLBOARD: + case BL::ParticleSettings::render_type_PATH: { /* for strand rendering */ + BL::ID key = (BKE_object_is_modified(b_ob))? b_ob: b_ob.data(); + Mesh *mesh = mesh_map.find(key); + if (mesh) { + use_particles |= mesh->need_attribute(scene, ATTR_STD_PARTICLE); + } + break; + } + #endif + + case BL::ParticleSettings::render_type_OBJECT: { + BL::Object b_dupli_ob = b_psys->settings().dupli_object(); + if (b_dupli_ob) { + BL::ID key = (BKE_object_is_modified(b_dupli_ob))? b_dupli_ob: b_dupli_ob.data(); + Mesh *mesh = mesh_map.find(key); + if (mesh) { + use_particles |= mesh->need_attribute(scene, ATTR_STD_PARTICLE); + } + } + break; + } + + case BL::ParticleSettings::render_type_GROUP: { + BL::Group b_dupli_group = b_psys->settings().dupli_group(); + if (b_dupli_group) { + BL::Group::objects_iterator b_gob; + for (b_dupli_group.objects.begin(b_gob); b_gob != b_dupli_group.objects.end(); ++b_gob) { + BL::ID key = (BKE_object_is_modified(*b_gob))? *b_gob: b_gob->data(); + Mesh *mesh = mesh_map.find(key); + if (mesh) { + use_particles |= mesh->need_attribute(scene, ATTR_STD_PARTICLE); + } + } + } + break; + } + } + } + + return use_particles; +} + +static bool use_particle_system(BL::ParticleSystem b_psys) +{ + /* only use duplicator particles? disabled particle info for + * halo and billboard to reduce particle count. + * Probably not necessary since particles don't contain a huge amount + * of data compared to other textures. + */ + #if 0 + int render_type = b_psys->settings().render_type(); + return (render_type == BL::ParticleSettings::render_type_OBJECT + || render_type == BL::ParticleSettings::render_type_GROUP); + #endif + + return true; +} + +static bool use_particle(BL::Particle b_pa) +{ + return b_pa.is_exist() && b_pa.is_visible() && b_pa.alive_state()==BL::Particle::alive_state_ALIVE; +} + +int BlenderSync::object_count_particles(BL::Object b_ob) +{ + int tot = 0; + BL::Object::particle_systems_iterator b_psys; + for(b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys) { + if (use_particle_system(*b_psys)) { + BL::ParticleSystem::particles_iterator b_pa; + for(b_psys->particles.begin(b_pa); b_pa != b_psys->particles.end(); ++b_pa) { + if(use_particle(*b_pa)) + ++tot; + } + } + } + return tot; +} + +void BlenderSync::sync_particles(Object *ob, BL::Object b_ob) +{ + int tot = object_count_particles(b_ob); + + ob->particles.clear(); + ob->particles.reserve(tot); + + int index; + BL::Object::particle_systems_iterator b_psys; + for(b_ob.particle_systems.begin(b_psys); b_psys != b_ob.particle_systems.end(); ++b_psys) { + if (use_particle_system(*b_psys)) { + BL::ParticleSystem::particles_iterator b_pa; + for(b_psys->particles.begin(b_pa), index=0; b_pa != b_psys->particles.end(); ++b_pa, ++index) { + if(use_particle(*b_pa)) { + Particle pa; + + pa.age = b_scene.frame_current() - b_pa->birth_time(); + pa.lifetime = b_pa->lifetime(); + + ob->particles.push_back(pa); + } + } + } + } +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 130b73a2808..a7be0a8fb54 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -337,6 +337,10 @@ static ShaderNode *add_node(BL::BlendData b_data, BL::Scene b_scene, ShaderGraph node = new ObjectInfoNode(); break; } + case BL::ShaderNode::type_PARTICLE_INFO: { + node = new ParticleInfoNode(); + break; + } case BL::ShaderNode::type_TEX_IMAGE: { BL::ShaderNodeTexImage b_image_node(b_node); BL::Image b_image(b_image_node.image()); diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index bc6258d35ac..8c31c4b86ba 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -80,17 +80,20 @@ private: void sync_nodes(Shader *shader, BL::ShaderNodeTree b_ntree); Mesh *sync_mesh(BL::Object b_ob, bool object_updated); - void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm, uint layer_flag, int motion); + void sync_object(BL::Object b_parent, int b_index, BL::Object b_object, Transform& tfm, uint layer_flag, int motion, int particle_id); void sync_light(BL::Object b_parent, int b_index, BL::Object b_ob, Transform& tfm); void sync_background_light(); void sync_mesh_motion(BL::Object b_ob, Mesh *mesh, int motion); void sync_camera_motion(BL::Object b_ob, int motion); + void sync_particles(Object *ob, BL::Object b_ob); /* util */ void find_shader(BL::ID id, vector<uint>& used_shaders, int default_shader); bool BKE_object_is_modified(BL::Object b_ob); bool object_is_mesh(BL::Object b_ob); bool object_is_light(BL::Object b_ob); + bool object_use_particles(BL::Object b_ob); + int object_count_particles(BL::Object b_ob); /* variables */ BL::BlendData b_data; diff --git a/intern/cycles/kernel/kernel_object.h b/intern/cycles/kernel/kernel_object.h index 05c45c490d8..18e0b1e8a87 100644 --- a/intern/cycles/kernel/kernel_object.h +++ b/intern/cycles/kernel/kernel_object.h @@ -154,10 +154,35 @@ __device_inline float object_random_number(KernelGlobals *kg, int object) return f.z; } +__device_inline uint object_particle_id(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 __float_as_int(f.w); +} + __device int shader_pass_id(KernelGlobals *kg, ShaderData *sd) { return kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*2 + 1); } +__device float particle_age(KernelGlobals *kg, int particle) +{ + int offset = particle*PARTICLE_SIZE; + float4 f = kernel_tex_fetch(__particles, offset); + return f.x; +} + +__device float particle_lifetime(KernelGlobals *kg, int particle) +{ + int offset = particle*PARTICLE_SIZE; + float4 f = kernel_tex_fetch(__particles, offset); + return f.y; +} + + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 482f886df3e..c1b8eed3dff 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -52,6 +52,9 @@ KERNEL_TEX(float4, texture_float4, __light_data) KERNEL_TEX(float2, texture_float2, __light_background_marginal_cdf) KERNEL_TEX(float2, texture_float2, __light_background_conditional_cdf) +/* particles */ +KERNEL_TEX(float4, texture_float4, __particles) + /* shaders */ KERNEL_TEX(uint4, texture_uint4, __svm_nodes) KERNEL_TEX(uint, texture_uint, __shader_flag) diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 4fd57a5f2b3..77a800b0e67 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -33,6 +33,7 @@ CCL_NAMESPACE_BEGIN #define LIGHT_SIZE 4 #define FILTER_TABLE_SIZE 256 #define RAMP_TABLE_SIZE 256 +#define PARTICLE_SIZE 1 #define TIME_INVALID FLT_MAX /* device capabilities */ @@ -359,6 +360,7 @@ typedef enum AttributeStandard { ATTR_STD_POSITION_UNDISPLACED, ATTR_STD_MOTION_PRE, ATTR_STD_MOTION_POST, + ATTR_STD_PARTICLE, ATTR_STD_NUM, ATTR_STD_NOT_FOUND = ~0 diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 6a05639beb9..8901e5e9628 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -269,6 +269,9 @@ __device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderT case NODE_OBJECT_INFO: svm_node_object_info(kg, sd, stack, node.y, node.z); break; + case NODE_PARTICLE_INFO: + svm_node_particle_info(kg, sd, stack, node.y, node.z); + break; #endif case NODE_CONVERT: svm_node_convert(sd, stack, node.y, node.z, node.w); diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h index dab19983946..88127b56474 100644 --- a/intern/cycles/kernel/svm/svm_geometry.h +++ b/intern/cycles/kernel/svm/svm_geometry.h @@ -94,5 +94,27 @@ __device void svm_node_object_info(KernelGlobals *kg, ShaderData *sd, float *sta stack_store_float(stack, out_offset, data); } +/* Particle Info */ + +__device void svm_node_particle_info(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset) +{ + float data; + + switch(type) { + case NODE_INFO_PAR_AGE: { + uint particle_id = object_particle_id(kg, sd->object); + data = particle_age(kg, particle_id); + stack_store_float(stack, out_offset, data); + break; + } + case NODE_INFO_PAR_LIFETIME: { + uint particle_id = object_particle_id(kg, sd->object); + data = particle_lifetime(kg, particle_id); + stack_store_float(stack, out_offset, data); + break; + } + } +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index 97849736ef6..2d756d57f41 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -93,7 +93,8 @@ typedef enum NodeType { NODE_RGB_CURVES = 6000, NODE_MIN_MAX = 6100, NODE_LIGHT_FALLOFF = 6200, - NODE_OBJECT_INFO = 6300 + NODE_OBJECT_INFO = 6300, + NODE_PARTICLE_INFO = 6400 } NodeType; typedef enum NodeAttributeType { @@ -117,6 +118,11 @@ typedef enum NodeObjectInfo { NODE_INFO_OB_RANDOM } NodeObjectInfo; +typedef enum NodeParticleInfo { + NODE_INFO_PAR_AGE, + NODE_INFO_PAR_LIFETIME +} NodeParticleInfo; + typedef enum NodeLightPath { NODE_LP_camera = 0, NODE_LP_shadow, diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 16c6b07261a..1c9eeacddbe 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1789,6 +1789,47 @@ void ObjectInfoNode::compile(OSLCompiler& compiler) compiler.add(this, "node_object_info"); } +/* Particle Info */ + +ParticleInfoNode::ParticleInfoNode() +: ShaderNode("particle_info") +{ + add_output("Age", SHADER_SOCKET_FLOAT); + add_output("Lifetime", SHADER_SOCKET_FLOAT); +} + +void ParticleInfoNode::attributes(AttributeRequestSet *attributes) +{ + if(!output("Age")->links.empty()) + attributes->add(ATTR_STD_PARTICLE); + if(!output("Lifetime")->links.empty()) + attributes->add(ATTR_STD_PARTICLE); + + ShaderNode::attributes(attributes); +} + +void ParticleInfoNode::compile(SVMCompiler& compiler) +{ + ShaderOutput *out; + + out = output("Age"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_AGE, out->stack_offset); + } + + out = output("Lifetime"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LIFETIME, out->stack_offset); + } +} + +void ParticleInfoNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_particle_info"); +} + /* Value */ ValueNode::ValueNode() diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 2d0d58d1e94..650758a6113 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -290,6 +290,12 @@ public: SHADER_NODE_CLASS(ObjectInfoNode) }; +class ParticleInfoNode : public ShaderNode { +public: + SHADER_NODE_CLASS(ParticleInfoNode) + void attributes(AttributeRequestSet *attributes); +}; + class ValueNode : public ShaderNode { public: SHADER_NODE_CLASS(ValueNode) diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 5c7e48a38eb..259a0d25bcc 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -25,6 +25,7 @@ #include "util_foreach.h" #include "util_map.h" #include "util_progress.h" +#include "util_vector.h" CCL_NAMESPACE_BEGIN @@ -38,6 +39,7 @@ Object::Object() visibility = ~0; random_id = 0; pass_id = 0; + particle_id = 0; bounds = BoundBox::empty; motion.pre = transform_identity(); motion.post = transform_identity(); @@ -200,7 +202,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, random_number, 0.0f); + objects[offset+6] = make_float4(surface_area, pass_id, random_number, __int_as_float(ob->particle_id)); if(need_motion == Scene::MOTION_PASS) { /* motion transformations, is world/object space depending if mesh @@ -246,6 +248,38 @@ void ObjectManager::device_update_transforms(Device *device, DeviceScene *dscene device->tex_alloc("__object_flag", dscene->object_flag); } +void ObjectManager::device_update_particles(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) +{ + /* count particles. + * adds one dummy particle at the beginning to avoid invalid lookups, + * in case a shader uses particle info without actual particle data. + */ + int num_particles = 1; + foreach(Object *ob, scene->objects) + num_particles += ob->particles.size(); + + float4 *particles = dscene->particles.resize(PARTICLE_SIZE*num_particles); + + /* dummy particle */ + particles[0] = make_float4(0.0f, 0.0f, 0.0f, 0.0f); + + int i = 1; + foreach(Object *ob, scene->objects) { + foreach(Particle &pa, ob->particles) { + /* pack in texture */ + int offset = i*PARTICLE_SIZE; + + particles[offset] = make_float4(pa.age, pa.lifetime, 0.0f, 0.0f); + + i++; + + if(progress.get_cancel()) return; + } + } + + device->tex_alloc("__particles", dscene->particles); +} + void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) { if(!need_update) @@ -271,6 +305,11 @@ void ObjectManager::device_update(Device *device, DeviceScene *dscene, Scene *sc if(progress.get_cancel()) return; + progress.set_status("Updating Objects", "Copying Particles to device"); + device_update_particles(device, dscene, scene, progress); + + if(progress.get_cancel()) return; + need_update = false; } @@ -281,6 +320,9 @@ void ObjectManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->object_flag); dscene->object_flag.clear(); + + device->tex_free(dscene->particles); + dscene->particles.clear(); } void ObjectManager::apply_static_transforms(Scene *scene, Progress& progress) diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h index a3bd748a8a4..6d674731b07 100644 --- a/intern/cycles/render/object.h +++ b/intern/cycles/render/object.h @@ -35,6 +35,11 @@ struct Transform; /* Object */ +struct Particle { + float age; + float lifetime; +}; + class Object { public: Mesh *mesh; @@ -49,6 +54,9 @@ public: bool use_motion; bool use_holdout; + int particle_id; + vector<Particle> particles; + Object(); ~Object(); @@ -69,6 +77,7 @@ public: void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); void device_update_transforms(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); + void device_update_particles(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); void device_free(Device *device, DeviceScene *dscene); void tag_update(Scene *scene); diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 90bc47d5c8e..8b9944cb76e 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -82,6 +82,9 @@ public: device_vector<float2> light_background_marginal_cdf; device_vector<float2> light_background_conditional_cdf; + /* particles */ + device_vector<float4> particles; + /* shaders */ device_vector<uint4> svm_nodes; device_vector<uint> shader_flag; diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 5fbd58e26a5..b1e5fabc456 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -527,6 +527,7 @@ struct ShadeResult; #define SH_NODE_BRIGHTCONTRAST 165 #define SH_NODE_LIGHT_FALLOFF 166 #define SH_NODE_OBJECT_INFO 167 +#define SH_NODE_PARTICLE_INFO 168 /* custom defines options for Material node */ #define SH_NODE_MAT_DIFF 1 diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index f73221066b1..701ce6c8299 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -75,7 +75,7 @@ /* --------------------- */ /* forward declarations */ -static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level, int animated); +static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int par_index, int level, int animated); /* ******************************************************************** */ /* Animation Visualisation */ @@ -699,7 +699,7 @@ int where_on_path(Object *ob, float ctime, float vec[4], float dir[3], float qua /* ******************************************************************** */ /* Dupli-Geometry */ -static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index, int type, int animated) +static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], int lay, int index, int par_index, int type, int animated) { DupliObject *dob = MEM_callocN(sizeof(DupliObject), "dupliobject"); @@ -709,6 +709,7 @@ static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], i copy_m4_m4(dob->omat, ob->obmat); dob->origlay = ob->lay; dob->index = index; + dob->particle_index = par_index; dob->type = type; dob->animated = (type == OB_DUPLIGROUP) && animated; ob->lay = lay; @@ -716,7 +717,7 @@ static DupliObject *new_dupli_object(ListBase *lb, Object *ob, float mat[][4], i return dob; } -static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated) +static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index, int level, int animated) { DupliObject *dob; Group *group; @@ -748,7 +749,7 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, i mult_m4_m4m4(mat, ob->obmat, go->ob->obmat); } - dob = new_dupli_object(lb, go->ob, mat, ob->lay, 0, OB_DUPLIGROUP, animated); + dob = new_dupli_object(lb, go->ob, mat, ob->lay, 0, par_index, OB_DUPLIGROUP, animated); /* check the group instance and object layers match, also that the object visible flags are ok. */ if ((dob->origlay & group->layer) == 0 || @@ -763,14 +764,14 @@ static void group_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, i if (go->ob->transflag & OB_DUPLI) { copy_m4_m4(dob->ob->obmat, dob->mat); - object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, level + 1, animated); + object_duplilist_recursive(&group->id, scene, go->ob, lb, ob->obmat, par_index, level + 1, animated); copy_m4_m4(dob->ob->obmat, dob->omat); } } } } -static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, int animated) +static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int par_index, int level, int animated) { extern int enable_cu_speed; /* object.c */ Object copyob; @@ -818,7 +819,7 @@ static void frames_duplilist(ListBase *lb, Scene *scene, Object *ob, int level, BKE_animsys_evaluate_animdata(scene, &ob->id, ob->adt, (float)scene->r.cfra, ADT_RECALC_ANIM); /* ob-eval will do drivers, so we don't need to do them */ BKE_object_where_is_calc_time(scene, ob, (float)scene->r.cfra); - dob = new_dupli_object(lb, ob, ob->obmat, ob->lay, scene->r.cfra, OB_DUPLIFRAMES, animated); + dob = new_dupli_object(lb, ob, ob->obmat, ob->lay, scene->r.cfra, par_index, OB_DUPLIFRAMES, animated); copy_m4_m4(dob->omat, copyob.obmat); } } @@ -849,6 +850,7 @@ typedef struct vertexDupliData { Scene *scene; Object *ob, *par; float (*orco)[3]; + int par_index; } vertexDupliData; /* ------------- */ @@ -885,7 +887,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], origlay = vdd->ob->lay; - dob = new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index, OB_DUPLIVERTS, vdd->animated); + dob = new_dupli_object(vdd->lb, vdd->ob, obmat, vdd->par->lay, index, vdd->par_index, OB_DUPLIVERTS, vdd->animated); /* restore the original layer so that each dupli will have proper dob->origlay */ vdd->ob->lay = origlay; @@ -897,12 +899,12 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3], float tmpmat[4][4]; copy_m4_m4(tmpmat, vdd->ob->obmat); copy_m4_m4(vdd->ob->obmat, obmat); /* pretend we are really this mat */ - object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->level + 1, vdd->animated); + object_duplilist_recursive((ID *)vdd->id, vdd->scene, vdd->ob, vdd->lb, obmat, vdd->par_index, vdd->level + 1, vdd->animated); copy_m4_m4(vdd->ob->obmat, tmpmat); } } -static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated) +static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int par_index, int level, int animated) { Object *ob, *ob_iter; Mesh *me = par->data; @@ -986,6 +988,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl vdd.scene = scene; vdd.par = par; copy_m4_m4(vdd.pmat, pmat); + vdd.par_index = par_index; /* mballs have a different dupli handling */ if (ob->type != OB_MBALL) ob->flag |= OB_DONE; /* doesnt render */ @@ -1024,7 +1027,7 @@ static void vertex_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, fl dm->release(dm); } -static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int level, int animated) +static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int par_index, int level, int animated) { Object *ob, *ob_iter; Base *base = NULL; @@ -1171,7 +1174,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa copy_m4_m4(tmat, obmat); mul_m4_m4m3(obmat, tmat, mat); - dob = new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIFACES, animated); + dob = new_dupli_object(lb, ob, obmat, par->lay, a, par_index, OB_DUPLIFACES, animated); if (G.rendering) { w = 1.0f / (float)mp->totloop; @@ -1194,7 +1197,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa float tmpmat[4][4]; copy_m4_m4(tmpmat, ob->obmat); copy_m4_m4(ob->obmat, obmat); /* pretend we are really this mat */ - object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, level + 1, animated); + object_duplilist_recursive((ID *)id, scene, ob, lb, ob->obmat, par_index, level + 1, animated); copy_m4_m4(ob->obmat, tmpmat); } } @@ -1214,7 +1217,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa dm->release(dm); } -static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated) +static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], int UNUSED(par_index), ParticleSystem *psys, int level, int animated) { GroupObject *go; Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL; @@ -1228,7 +1231,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p float ctime, pa_time, scale = 1.0f; float tmat[4][4], mat[4][4], pamat[4][4], vec[3], size = 0.0; float (*obmat)[4], (*oldobmat)[4]; - int a, b, counter, hair = 0; + int a, b, counter, index, hair = 0; int totpart, totchild, totgroup = 0 /*, pa_num */; int no_draw_flag = PARS_UNEXIST; @@ -1342,6 +1345,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p else a = totpart; + index = 0; for (pa = psys->particles, counter = 0; a < totpart + totchild; a++, pa++, counter++) { if (a < totpart) { /* handle parent particle */ @@ -1437,7 +1441,7 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p else copy_m4_m4(mat, tmat); - dob = new_dupli_object(lb, go->ob, mat, par->lay, counter, OB_DUPLIPARTS, animated); + dob = new_dupli_object(lb, go->ob, mat, par->lay, counter, index, OB_DUPLIPARTS, animated); copy_m4_m4(dob->omat, obcopylist[b].obmat); if (G.rendering) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); @@ -1479,11 +1483,14 @@ static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *p if (part->draw & PART_DRAW_GLOBAL_OB) add_v3_v3v3(mat[3], mat[3], vec); - dob = new_dupli_object(lb, ob, mat, ob->lay, counter, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated); + dob = new_dupli_object(lb, ob, mat, ob->lay, counter, index, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated); copy_m4_m4(dob->omat, oldobmat); if (G.rendering) psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco); } + + /* only counts visible particles */ + ++index; } /* restore objects since they were changed in BKE_object_where_is_calc_time */ @@ -1530,7 +1537,7 @@ static Object *find_family_object(Object **obar, char *family, char ch) } -static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int level, int animated) +static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int par_index, int level, int animated) { Object *ob, *obar[256] = {NULL}; Curve *cu; @@ -1569,7 +1576,7 @@ static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int level, i copy_m4_m4(obmat, par->obmat); copy_v3_v3(obmat[3], vec); - new_dupli_object(lb, ob, obmat, par->lay, a, OB_DUPLIVERTS, animated); + new_dupli_object(lb, ob, obmat, par->lay, a, par_index, OB_DUPLIVERTS, animated); } } @@ -1578,7 +1585,7 @@ static void font_duplilist(ListBase *lb, Scene *scene, Object *par, int level, i /* ------------- */ -static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int level, int animated) +static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBase *duplilist, float par_space_mat[][4], int par_index, int level, int animated) { if ((ob->transflag & OB_DUPLI) == 0) return; @@ -1598,31 +1605,31 @@ static void object_duplilist_recursive(ID *id, Scene *scene, Object *ob, ListBas if (ob->transflag & OB_DUPLIPARTS) { ParticleSystem *psys = ob->particlesystem.first; for (; psys; psys = psys->next) - new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, psys, level + 1, animated); + new_particle_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, psys, level + 1, animated); } else if (ob->transflag & OB_DUPLIVERTS) { if (ob->type == OB_MESH) { - vertex_duplilist(duplilist, id, scene, ob, par_space_mat, level + 1, animated); + vertex_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, animated); } else if (ob->type == OB_FONT) { if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */ - font_duplilist(duplilist, scene, ob, level + 1, animated); + font_duplilist(duplilist, scene, ob, par_index, level + 1, animated); } } } else if (ob->transflag & OB_DUPLIFACES) { if (ob->type == OB_MESH) - face_duplilist(duplilist, id, scene, ob, par_space_mat, level + 1, animated); + face_duplilist(duplilist, id, scene, ob, par_space_mat, par_index, level + 1, animated); } else if (ob->transflag & OB_DUPLIFRAMES) { if (GS(id->name) == ID_SCE) { /* TODO - support dupligroups */ - frames_duplilist(duplilist, scene, ob, level + 1, animated); + frames_duplilist(duplilist, scene, ob, par_index, level + 1, animated); } } else if (ob->transflag & OB_DUPLIGROUP) { DupliObject *dob; - group_duplilist(duplilist, scene, ob, level + 1, animated); /* now recursive */ + group_duplilist(duplilist, scene, ob, par_index, level + 1, animated); /* now recursive */ if (level == 0) { for (dob = duplilist->first; dob; dob = dob->next) @@ -1638,7 +1645,7 @@ ListBase *object_duplilist(Scene *sce, Object *ob) { ListBase *duplilist = MEM_mallocN(sizeof(ListBase), "duplilist"); duplilist->first = duplilist->last = NULL; - object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0); + object_duplilist_recursive((ID *)sce, sce, ob, duplilist, NULL, 0, 0, 0); return duplilist; } diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 86a1f715c3c..d62e91dbde5 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1956,6 +1956,7 @@ static void registerShaderNodes(bNodeTreeType *ttype) register_node_type_sh_fresnel(ttype); register_node_type_sh_layer_weight(ttype); register_node_type_sh_tex_coord(ttype); + register_node_type_sh_particle_info(ttype); register_node_type_sh_background(ttype); register_node_type_sh_bsdf_diffuse(ttype); diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 44d7ec660f2..24d33b49db2 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -301,6 +301,15 @@ typedef struct DupliObject { short type; /* from Object.transflag */ char no_draw, animated; + + /* Lowest-level particle index. + * Note: This is needed for particle info in shaders. + * Otherwise dupli groups in particle systems would override the + * index value from higher dupli levels. Would be nice to have full generic access + * to all dupli levels somehow, but for now this should cover most use-cases. + */ + int particle_index; + int pad; } DupliObject; /* **************** OBJECT ********************* */ diff --git a/source/blender/makesrna/intern/rna_nodetree_types.h b/source/blender/makesrna/intern/rna_nodetree_types.h index 2b8050adca7..3981afe5349 100644 --- a/source/blender/makesrna/intern/rna_nodetree_types.h +++ b/source/blender/makesrna/intern/rna_nodetree_types.h @@ -80,6 +80,7 @@ DefNode( ShaderNode, SH_NODE_NEW_GEOMETRY, 0, "NE 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_PARTICLE_INFO, 0, "PARTICLE_INFO", ParticleInfo, "Particle 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", "" ) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 7e3b368aa64..0399a8ee60d 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2545,6 +2545,16 @@ static void rna_def_dupli_object(BlenderRNA *brna) RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); RNA_def_property_ui_text(prop, "Hide", "Don't show dupli object in viewport or render"); + prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "index"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Index", "Index in the lowest-level dupli list"); + + prop = RNA_def_property(srna, "particle_index", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "particle_index"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE | PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Particle Index", "Index in the lowest-level particle dupli list"); + /* TODO: DupliObject has more properties that can be wrapped */ } diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index c637e3606f1..8b2a5ebd263 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -159,6 +159,7 @@ set(SRC 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_particle_info.c shader/nodes/node_shader_mix_shader.c shader/nodes/node_shader_add_shader.c shader/nodes/node_shader_output_lamp.c diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h index dd6d25380b4..6b000181953 100644 --- a/source/blender/nodes/NOD_shader.h +++ b/source/blender/nodes/NOD_shader.h @@ -78,6 +78,7 @@ 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); +void register_node_type_sh_particle_info(struct bNodeTreeType *ttype); void register_node_type_sh_background(struct bNodeTreeType *ttype); void register_node_type_sh_bsdf_diffuse(struct bNodeTreeType *ttype); diff --git a/source/blender/nodes/shader/nodes/node_shader_particle_info.c b/source/blender/nodes/shader/nodes/node_shader_particle_info.c new file mode 100644 index 00000000000..6456742e22b --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.c @@ -0,0 +1,48 @@ +/* + * ***** 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" + +static bNodeSocketTemplate outputs[] = { + { SOCK_FLOAT, 0, "Age" }, + { SOCK_FLOAT, 0, "Lifetime" }, + { -1, 0, "" } +}; + +/* node type definition */ +void register_node_type_sh_particle_info(bNodeTreeType *ttype) +{ + static bNodeType ntype; + + node_type_base(ttype, &ntype, SH_NODE_PARTICLE_INFO, "Particle Info", NODE_CLASS_INPUT, 0); + node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_socket_templates(&ntype, NULL, outputs); + node_type_size(&ntype, 150, 60, 200); + + nodeRegisterType(ttype, &ntype); +} + |