Files
test2/source/blender/blenkernel/intern/effect.cc

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1409 lines
39 KiB
C++
Raw Normal View History

/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later */
2002-10-12 11:37:38 +00:00
/** \file
* \ingroup bke
2011-02-27 20:40:57 +00:00
*/
#include <cstdarg>
#include <cstddef>
#include <cmath>
#include <cstdlib>
2002-10-12 11:37:38 +00:00
#include "MEM_guardedalloc.h"
Orange branch: Revived hidden treasure, the Groups! Previous experiment (in 2000) didn't satisfy, it had even some primitive NLA option in groups... so, cleaned up the old code (removed most) and integrated it back in a more useful way. Usage: - CTRL+G gives menu to add group, add to existing group, or remove from groups. - In Object buttons, a new (should become first) Panel was added, showing not only Object "ID button" and Parent, but also the Groups the Object Belongs to. These buttons also allow rename, assigning or removing. - To indicate Objects are grouped, they're drawn in a (not theme yet, so temporal?) green wire color. - Use ALT+SHIFT mouse-select to (de)select an entire group But, the real power of groups is in the following features: -> Particle Force field and Guide control In the "Particle Motion" Panel, you can indicate a Group name, this then limits force fields or guides to members of that Group. (Note that layers still work on top of that... not sure about that). -> Light Groups In the Material "Shaders" Panel, you can indicate a Group name to limit lighting for the Material to lamps in this group. The Lights in a Group do need to be 'visible' for the Scene to be rendered (as usual). -> Group Duplicator In the Object "Anim" Panel, you can set any Object (use Empty!) to duplicate an entire Group. It will make copies of all Objects in that Group. Also works for animated Objects, but it will copy the current positions or deforms. Control over 'local timing' (so we can do Massive anims!) will be added later. (Note; this commit won't render Group duplicators yet, a fix in bf-blender will enable that, next commit will sync) -> Library Appending In the SHIFT-F1 or SHIFT+F4 browsers, you can also find the Groups listed. By appending or linking the Group itself, and use the Group Duplicator, you now can animate and position linked Objects. The nice thing is that the local saved file itself will only store the Group name that was linked, so on a next file read, the Group Objects will be re-read as stored (changed) in the Library file. (Note; current implementation also "gives a base" to linked Group Objects, to show them as Objects in the current Scene. Need that now for testing purposes, but probably will be removed later). -> Outliner Outliner now shows Groups as optio too, nice to organize your data a bit too! In General, Groups have a very good potential... for example, it could become default for MetaBall Objects too (jiri, I can help you later on how this works). All current 'layer relationships' in Blender should be dropped in time, I guess...
2005-12-06 10:55:30 +00:00
#include "DNA_collection_types.h"
Orange branch: Revived hidden treasure, the Groups! Previous experiment (in 2000) didn't satisfy, it had even some primitive NLA option in groups... so, cleaned up the old code (removed most) and integrated it back in a more useful way. Usage: - CTRL+G gives menu to add group, add to existing group, or remove from groups. - In Object buttons, a new (should become first) Panel was added, showing not only Object "ID button" and Parent, but also the Groups the Object Belongs to. These buttons also allow rename, assigning or removing. - To indicate Objects are grouped, they're drawn in a (not theme yet, so temporal?) green wire color. - Use ALT+SHIFT mouse-select to (de)select an entire group But, the real power of groups is in the following features: -> Particle Force field and Guide control In the "Particle Motion" Panel, you can indicate a Group name, this then limits force fields or guides to members of that Group. (Note that layers still work on top of that... not sure about that). -> Light Groups In the Material "Shaders" Panel, you can indicate a Group name to limit lighting for the Material to lamps in this group. The Lights in a Group do need to be 'visible' for the Scene to be rendered (as usual). -> Group Duplicator In the Object "Anim" Panel, you can set any Object (use Empty!) to duplicate an entire Group. It will make copies of all Objects in that Group. Also works for animated Objects, but it will copy the current positions or deforms. Control over 'local timing' (so we can do Massive anims!) will be added later. (Note; this commit won't render Group duplicators yet, a fix in bf-blender will enable that, next commit will sync) -> Library Appending In the SHIFT-F1 or SHIFT+F4 browsers, you can also find the Groups listed. By appending or linking the Group itself, and use the Group Duplicator, you now can animate and position linked Objects. The nice thing is that the local saved file itself will only store the Group name that was linked, so on a next file read, the Group Objects will be re-read as stored (changed) in the Library file. (Note; current implementation also "gives a base" to linked Group Objects, to show them as Objects in the current Scene. Need that now for testing purposes, but probably will be removed later). -> Outliner Outliner now shows Groups as optio too, nice to organize your data a bit too! In General, Groups have a very good potential... for example, it could become default for MetaBall Objects too (jiri, I can help you later on how this works). All current 'layer relationships' in Blender should be dropped in time, I guess...
2005-12-06 10:55:30 +00:00
#include "DNA_curve_types.h"
#include "DNA_listBase.h"
2018-06-26 17:45:00 +02:00
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
2002-10-12 11:37:38 +00:00
#include "DNA_scene_types.h"
#include "DNA_texture_types.h"
2002-10-12 11:37:38 +00:00
Giant commit! A full detailed description of this will be done later... is several days of work. Here's a summary: Render: - Full cleanup of render code, removing *all* globals and bad level calls all over blender. Render module is now not called abusive anymore - API-fied calls to rendering - Full recode of internal render pipeline. Is now rendering tiles by default, prepared for much smarter 'bucket' render later. - Each thread now can render a full part - Renders were tested with 4 threads, goes fine, apart from some lookup tables in softshadow and AO still - Rendering is prepared to do multiple layers and passes - No single 32 bits trick in render code anymore, all 100% floats now. Writing images/movies - moved writing images to blender kernel (bye bye 'schrijfplaatje'!) - made a new Movie handle system, also in kernel. This will enable much easier use of movies in Blender PreviewRender: - Using new render API, previewrender (in buttons) now uses regular render code to generate images. - new datafile 'preview.blend.c' has the preview scenes in it - previews get rendered in exact displayed size (1 pixel = 1 pixel) 3D Preview render - new; press Pkey in 3d window, for a panel that continuously renders (pkey is for games, i know... but we dont do that in orange now!) - this render works nearly identical to buttons-preview render, so it stops rendering on any event (mouse, keyboard, etc) - on moving/scaling the panel, the render code doesn't recreate all geometry - same for shifting/panning view - all other operations (now) regenerate the full render database still. - this is WIP... but big fun, especially for simple scenes! Compositor - Using same node system as now in use for shaders, you can composit images - works pretty straightforward... needs much more options/tools and integration with rendering still - is not threaded yet, nor is so smart to only recalculate changes... will be done soon! - the "Render Result" node will get all layers/passes as output sockets - The "Output" node renders to a builtin image, which you can view in the Image window. (yes, output nodes to render-result, and to files, is on the list!) The Bad News - "Unified Render" is removed. It might come back in some stage, but this system should be built from scratch. I can't really understand this code... I expect it is not much needed, especially with advanced layer/passes control - Panorama render, Field render, Motion blur, is not coded yet... (I had to recode every single feature in render, so...!) - Lens Flare is also not back... needs total revision, might become composit effect though (using zbuffer for visibility) - Part render is gone! (well, thats obvious, its default now). - The render window is only restored with limited functionality... I am going to check first the option to render to a Image window, so Blender can become a true single-window application. :) For example, the 'Spare render buffer' (jkey) doesnt work. - Render with border, now default creates a smaller image - No zbuffers are written yet... on the todo! - Scons files and MSVC will need work to get compiling again OK... thats what I can quickly recall. Now go compiling!
2006-01-23 22:05:47 +00:00
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
#include "BLI_math_matrix.h"
#include "BLI_math_rotation.h"
#include "BLI_math_vector.h"
#include "BLI_noise.h"
2002-10-12 11:37:38 +00:00
#include "BLI_rand.h"
#include "BLI_utildefines.h"
2002-10-12 11:37:38 +00:00
#include "PIL_time.h"
#include "BKE_anim_path.h" /* needed for where_on_path */
2018-06-26 17:45:00 +02:00
#include "BKE_bvhutils.h"
Collections and groups unification OVERVIEW * In 2.7 terminology, all layers and groups are now collection datablocks. * These collections are nestable, linkable, instanceable, overrideable, .. which opens up new ways to set up scenes and link + override data. * Viewport/render visibility and selectability are now a part of the collection and shared across all view layers and linkable. * View layers define which subset of the scene collection hierarchy is excluded for each. For many workflows one view layer can be used, these are more of an advanced feature now. OUTLINER * The outliner now has a "View Layer" display mode instead of "Collections", which can display the collections and/or objects in the view layer. * In this display mode, collections can be excluded with the right click menu. These will then be greyed out and their objects will be excluded. * To view collections not linked to any scene, the "Blender File" display mode can be used, with the new filtering option to just see Colleciton datablocks. * The outliner right click menus for collections and objects were reorganized. * Drag and drop still needs to be improved. Like before, dragging the icon or text gives different results, we'll unify this later. LINKING AND OVERRIDES * Collections can now be linked into the scene without creating an instance, with the link/append operator or from the collections view in the outliner. * Collections can get static overrides with the right click menu in the outliner, but this is rather unreliable and not clearly communicated at the moment. * We still need to improve the make override operator to turn collection instances into collections with overrides directly in the scene. PERFORMANCE * We tried to make performance not worse than before and improve it in some cases. The main thing that's still a bit slower is multiple scenes, we have to change the layer syncing to only updated affected scenes. * Collections keep a list of their parent collections for faster incremental updates in syncing and caching. * View layer bases are now in a object -> base hash to avoid quadratic time lookups internally and in API functions like visible_get(). VERSIONING * Compatibility with 2.7 files should be improved due to the new visibility controls. Of course users may not want to set up their scenes differently now to avoid having separate layers and groups. * Compatibility with 2.8 is mostly there, and was tested on Eevee demo and Hero files. There's a few things which are know to be not quite compatible, like nested layer collections inside groups. * The versioning code for 2.8 files is quite complicated, and isolated behind #ifdef so it can be removed at the end of the release cycle. KNOWN ISSUES * The G-key group operators in the 3D viewport were left mostly as is, they need to be modified still to fit better. * Same for the groups panel in the object properties. This needs to be updated still, or perhaps replaced by something better. * Collections must all have a unique name. Less restrictive namespacing is to be done later, we'll have to see how important this is as all objects within the collections must also have a unique name anyway. * Full scene copy and delete scene are exactly doing the right thing yet. Differential Revision: https://developer.blender.org/D3383 https://code.blender.org/2018/05/collections-and-groups/
2018-04-30 15:57:22 +02:00
#include "BKE_collection.h"
#include "BKE_collision.h"
#include "BKE_curve.h"
2002-10-12 11:37:38 +00:00
#include "BKE_displist.h"
#include "BKE_effect.h"
#include "BKE_fluid.h"
#include "BKE_global.h"
2017-04-21 14:28:23 +02:00
#include "BKE_layer.h"
#include "BKE_mesh.hh"
#include "BKE_modifier.h"
#include "BKE_object.hh"
#include "BKE_particle.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.hh"
#include "DEG_depsgraph_physics.hh"
#include "DEG_depsgraph_query.hh"
Phew, a lot of work, and no new features... Main target was to make the inner rendering loop using no globals anymore. This is essential for proper usage while raytracing, it caused a lot of hacks in the raycode as well, which even didn't work correctly for all situations (textures especially). Done this by creating a new local struct RenderInput, which replaces usage of the global struct Render R. The latter now only is used to denote image size, viewmatrix, and the like. Making the inner render loops using no globals caused 1000s of vars to be changed... but the result definitely is much nicer code, which enables making 'real' shaders in a next stage. It also enabled me to remove the hacks from ray.c Then i went to the task of removing redundant code. Especially the calculus of texture coords took place (identical) in three locations. Most obvious is the change in the unified render part, which is much less code now; it uses the same rendering routines as normal render now. (Note; not for halos yet!) I also removed 6 files called 'shadowbuffer' something. This was experimen- tal stuff from NaN days. And again saved a lot of double used code. Finally I went over the blenkernel and blender/src calls to render stuff. Here the same local data is used now, resulting in less dependency. I also moved render-texture to the render module, this was still in Kernel. (new file: texture.c) So! After this commit I will check on the autofiles, to try to fix that. MSVC people have to do it themselves. This commit will need quite some testing help, but I'm around!
2003-12-21 21:52:51 +00:00
#include "RE_texture.h"
Giant commit! A full detailed description of this will be done later... is several days of work. Here's a summary: Render: - Full cleanup of render code, removing *all* globals and bad level calls all over blender. Render module is now not called abusive anymore - API-fied calls to rendering - Full recode of internal render pipeline. Is now rendering tiles by default, prepared for much smarter 'bucket' render later. - Each thread now can render a full part - Renders were tested with 4 threads, goes fine, apart from some lookup tables in softshadow and AO still - Rendering is prepared to do multiple layers and passes - No single 32 bits trick in render code anymore, all 100% floats now. Writing images/movies - moved writing images to blender kernel (bye bye 'schrijfplaatje'!) - made a new Movie handle system, also in kernel. This will enable much easier use of movies in Blender PreviewRender: - Using new render API, previewrender (in buttons) now uses regular render code to generate images. - new datafile 'preview.blend.c' has the preview scenes in it - previews get rendered in exact displayed size (1 pixel = 1 pixel) 3D Preview render - new; press Pkey in 3d window, for a panel that continuously renders (pkey is for games, i know... but we dont do that in orange now!) - this render works nearly identical to buttons-preview render, so it stops rendering on any event (mouse, keyboard, etc) - on moving/scaling the panel, the render code doesn't recreate all geometry - same for shifting/panning view - all other operations (now) regenerate the full render database still. - this is WIP... but big fun, especially for simple scenes! Compositor - Using same node system as now in use for shaders, you can composit images - works pretty straightforward... needs much more options/tools and integration with rendering still - is not threaded yet, nor is so smart to only recalculate changes... will be done soon! - the "Render Result" node will get all layers/passes as output sockets - The "Output" node renders to a builtin image, which you can view in the Image window. (yes, output nodes to render-result, and to files, is on the list!) The Bad News - "Unified Render" is removed. It might come back in some stage, but this system should be built from scratch. I can't really understand this code... I expect it is not much needed, especially with advanced layer/passes control - Panorama render, Field render, Motion blur, is not coded yet... (I had to recode every single feature in render, so...!) - Lens Flare is also not back... needs total revision, might become composit effect though (using zbuffer for visibility) - Part render is gone! (well, thats obvious, its default now). - The render window is only restored with limited functionality... I am going to check first the option to render to a Image window, so Blender can become a true single-window application. :) For example, the 'Spare render buffer' (jkey) doesnt work. - Render with border, now default creates a smaller image - No zbuffers are written yet... on the todo! - Scons files and MSVC will need work to get compiling again OK... thats what I can quickly recall. Now go compiling!
2006-01-23 22:05:47 +00:00
2018-12-02 14:15:43 +11:00
EffectorWeights *BKE_effector_add_weights(Collection *collection)
{
EffectorWeights *weights = static_cast<EffectorWeights *>(
MEM_callocN(sizeof(EffectorWeights), "EffectorWeights"));
2020-09-09 16:35:20 +02:00
for (int i = 0; i < NUM_PFIELD_TYPES; i++) {
weights->weight[i] = 1.0f;
2018-09-25 11:41:29 +10:00
}
weights->global_gravity = 1.0f;
Collections and groups unification OVERVIEW * In 2.7 terminology, all layers and groups are now collection datablocks. * These collections are nestable, linkable, instanceable, overrideable, .. which opens up new ways to set up scenes and link + override data. * Viewport/render visibility and selectability are now a part of the collection and shared across all view layers and linkable. * View layers define which subset of the scene collection hierarchy is excluded for each. For many workflows one view layer can be used, these are more of an advanced feature now. OUTLINER * The outliner now has a "View Layer" display mode instead of "Collections", which can display the collections and/or objects in the view layer. * In this display mode, collections can be excluded with the right click menu. These will then be greyed out and their objects will be excluded. * To view collections not linked to any scene, the "Blender File" display mode can be used, with the new filtering option to just see Colleciton datablocks. * The outliner right click menus for collections and objects were reorganized. * Drag and drop still needs to be improved. Like before, dragging the icon or text gives different results, we'll unify this later. LINKING AND OVERRIDES * Collections can now be linked into the scene without creating an instance, with the link/append operator or from the collections view in the outliner. * Collections can get static overrides with the right click menu in the outliner, but this is rather unreliable and not clearly communicated at the moment. * We still need to improve the make override operator to turn collection instances into collections with overrides directly in the scene. PERFORMANCE * We tried to make performance not worse than before and improve it in some cases. The main thing that's still a bit slower is multiple scenes, we have to change the layer syncing to only updated affected scenes. * Collections keep a list of their parent collections for faster incremental updates in syncing and caching. * View layer bases are now in a object -> base hash to avoid quadratic time lookups internally and in API functions like visible_get(). VERSIONING * Compatibility with 2.7 files should be improved due to the new visibility controls. Of course users may not want to set up their scenes differently now to avoid having separate layers and groups. * Compatibility with 2.8 is mostly there, and was tested on Eevee demo and Hero files. There's a few things which are know to be not quite compatible, like nested layer collections inside groups. * The versioning code for 2.8 files is quite complicated, and isolated behind #ifdef so it can be removed at the end of the release cycle. KNOWN ISSUES * The G-key group operators in the 3D viewport were left mostly as is, they need to be modified still to fit better. * Same for the groups panel in the object properties. This needs to be updated still, or perhaps replaced by something better. * Collections must all have a unique name. Less restrictive namespacing is to be done later, we'll have to see how important this is as all objects within the collections must also have a unique name anyway. * Full scene copy and delete scene are exactly doing the right thing yet. Differential Revision: https://developer.blender.org/D3383 https://code.blender.org/2018/05/collections-and-groups/
2018-04-30 15:57:22 +02:00
weights->group = collection;
return weights;
}
2018-12-02 14:14:51 +11:00
PartDeflect *BKE_partdeflect_new(int type)
{
PartDeflect *pd;
pd = static_cast<PartDeflect *>(MEM_callocN(sizeof(PartDeflect), "PartDeflect"));
pd->forcefield = type;
pd->pdef_sbdamp = 0.1f;
pd->pdef_sbift = 0.2f;
pd->pdef_sboft = 0.02f;
pd->pdef_cfrict = 5.0f;
pd->seed = (uint(ceil(PIL_check_seconds_timer())) + 1) % 128;
pd->f_strength = 1.0f;
pd->f_damp = 1.0f;
/* set sensible defaults based on type */
switch (type) {
case PFIELD_VORTEX:
pd->shape = PFIELD_SHAPE_PLANE;
break;
case PFIELD_WIND:
pd->shape = PFIELD_SHAPE_PLANE;
pd->f_flow = 1.0f; /* realistic wind behavior */
pd->f_wind_factor = 1.0f; /* only act perpendicularly to a surface */
break;
case PFIELD_TEXTURE:
pd->f_size = 1.0f;
break;
case PFIELD_FLUIDFLOW:
pd->f_flow = 1.0f;
break;
}
pd->flag = PFIELD_DO_LOCATION | PFIELD_DO_ROTATION | PFIELD_CLOTH_USE_CULLING;
return pd;
}
/************************ PARTICLES ***************************/
PartDeflect *BKE_partdeflect_copy(const PartDeflect *pd_src)
{
if (pd_src == nullptr) {
return nullptr;
}
PartDeflect *pd_dst = static_cast<PartDeflect *>(MEM_dupallocN(pd_src));
if (pd_dst->rng != nullptr) {
pd_dst->rng = BLI_rng_copy(pd_dst->rng);
}
return pd_dst;
}
2018-12-02 14:14:51 +11:00
void BKE_partdeflect_free(PartDeflect *pd)
{
2018-09-25 11:41:29 +10:00
if (!pd) {
return;
2018-09-25 11:41:29 +10:00
}
if (pd->rng) {
BLI_rng_free(pd->rng);
2018-09-25 11:41:29 +10:00
}
MEM_freeN(pd);
}
/******************** EFFECTOR RELATIONS ***********************/
The long awaited Particle patch from Janne Karhu http://www.blender3d.org/cms/New_Particle_options_a.721.0.html There's no doubt this patch had a lot of good ideas for features, and I want to compliment Janne again for getting it all to work even! A more careful review of the features and code did show however quite some flaws and bugs... partially because the current particle code was very much polluted already, but also because of the implementation lacked quality. However, the patch was too good to reject, so I've fixed and recoded the parts that needed it most. :) Here's a list of of most evident changes in the patch; - Guides support recoded. It was implemented as a true 'force field', checking all Curve path points for each particle to find the closest. Was just far too slow, and didn't support looping or bends well. The new implementation is fast (real time) and treats the paths as actual trajectory for the particle. - Guides didn't integrate in the physics/speed system either, was added as exception. Now it's integrated and can be combined with other velocities or forces - Use of Fields was slow code in general, made it use a Cache instead. - The "even" distribution didn't work for Jittered sample patterns. - The "even" or "vertexgroup" code in the main loops were badly constructed, giving too much cpu for a simple task. Instead of going over all faces many times, it now only does it once. Same part of the code used a lot of temporal unneeded mallocs. - Use of DerivedMesh or Mesh was confused, didn't work for Subsurfs in all cases - Support for vertex groups was slow, evaluating vertexgroups too often - When a vertexgroup failed to read, it was wrongly handled (set to zero). VertexGroup support now is with a name. - Split up the too huge build_particle() call in some parts (moving new code) - The "texture re-timing" option failed for moving Objects. The old code used the convention that particles were added with increasing time steps. Solved by creating a object Matrix Cache. Also: the texture coordinates had to be corrected to become "OrCo". - The "Disp" option only was used to draw less particles. Changed it to actually calculate fewer particles for 3D viewing, but render all still. So now it can be used to keep editing realtime. Removed; The "speed threshold" and "Tight" features were not copied over. This resembled too much to feature overkill. Needs re-evaluation. Also the "Deform" option was not added, I prefer to first check if the current particle system really works for the Modifier system. And: - Added integration for particle force fields in the dependency graph - Added TAB completion for vertexgroup names! - Made the 'wait cursor' only appear when particles take more than 0.5 sec - The particle jitter table order now is randomized too, giving much nicer emitting of particles in large faces. - Vortex field didn't correctly use speed/forces, so it didn't work for collisions. - Triangle distribution was wrong - Removed ancient bug that applied in a *very* weird way speed and forces. (location changes got the half force, speed the full...???) So much... might have forgotten some notes! :)
2005-11-10 16:01:56 +00:00
static void precalculate_effector(Depsgraph *depsgraph, EffectorCache *eff)
{
float ctime = DEG_get_ctime(depsgraph);
uint cfra = uint(ctime >= 0 ? ctime : -ctime);
2018-09-25 11:42:44 +10:00
if (!eff->pd->rng) {
eff->pd->rng = BLI_rng_new(eff->pd->seed + cfra);
2018-09-25 11:42:44 +10:00
}
else {
BLI_rng_srandom(eff->pd->rng, eff->pd->seed + cfra);
2018-09-25 11:41:29 +10:00
}
if (eff->pd->forcefield == PFIELD_GUIDE && eff->ob->type == OB_CURVES_LEGACY) {
Curve *cu = static_cast<Curve *>(eff->ob->data);
if (cu->flag & CU_PATH) {
if (eff->ob->runtime.curve_cache == nullptr ||
eff->ob->runtime.curve_cache->anim_path_accum_length == nullptr)
{
BKE_displist_make_curveTypes(depsgraph, eff->scene, eff->ob, false);
}
if (eff->ob->runtime.curve_cache->anim_path_accum_length) {
BKE_where_on_path(
eff->ob, 0.0, eff->guide_loc, eff->guide_dir, nullptr, &eff->guide_radius, nullptr);
mul_m4_v3(eff->ob->object_to_world, eff->guide_loc);
mul_mat3_m4_v3(eff->ob->object_to_world, eff->guide_dir);
}
}
}
else if (eff->pd->shape == PFIELD_SHAPE_SURFACE) {
eff->surmd = (SurfaceModifierData *)BKE_modifiers_findby_type(eff->ob, eModifierType_Surface);
if (eff->ob->type == OB_CURVES_LEGACY) {
eff->flag |= PE_USE_NORMAL_DATA;
}
}
else if (eff->psys) {
psys_update_particle_tree(eff->psys, ctime);
}
}
static void add_effector_relation(ListBase *relations,
Object *ob,
ParticleSystem *psys,
PartDeflect *pd)
{
EffectorRelation *relation = static_cast<EffectorRelation *>(
MEM_callocN(sizeof(EffectorRelation), "EffectorRelation"));
relation->ob = ob;
relation->psys = psys;
relation->pd = pd;
BLI_addtail(relations, relation);
}
static void add_effector_evaluation(ListBase **effectors,
Depsgraph *depsgraph,
Scene *scene,
Object *ob,
ParticleSystem *psys,
PartDeflect *pd)
{
if (*effectors == nullptr) {
*effectors = static_cast<ListBase *>(MEM_callocN(sizeof(ListBase), "effector effectors"));
}
EffectorCache *eff = static_cast<EffectorCache *>(
MEM_callocN(sizeof(EffectorCache), "EffectorCache"));
eff->depsgraph = depsgraph;
eff->scene = scene;
eff->ob = ob;
eff->psys = psys;
eff->pd = pd;
eff->frame = -1;
BLI_addtail(*effectors, eff);
precalculate_effector(depsgraph, eff);
}
ListBase *BKE_effector_relations_create(Depsgraph *depsgraph,
const Scene *scene,
2018-09-25 11:42:44 +10:00
ViewLayer *view_layer,
Collection *collection)
{
Base *base = BKE_collection_or_layer_objects(scene, view_layer, collection);
const bool for_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
const int base_flag = (for_render) ? BASE_ENABLED_RENDER : BASE_ENABLED_VIEWPORT;
ListBase *relations = static_cast<ListBase *>(
MEM_callocN(sizeof(ListBase), "effector relations"));
for (; base; base = base->next) {
if (!(base->flag & base_flag)) {
continue;
}
Object *ob = base->object;
if (ob->pd && ob->pd->forcefield) {
add_effector_relation(relations, ob, nullptr, ob->pd);
}
LISTBASE_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
ParticleSettings *part = psys->part;
if (psys_check_enabled(ob, psys, for_render)) {
if (part->pd && part->pd->forcefield) {
add_effector_relation(relations, ob, psys, part->pd);
}
if (part->pd2 && part->pd2->forcefield) {
add_effector_relation(relations, ob, psys, part->pd2);
}
}
}
}
return relations;
}
void BKE_effector_relations_free(ListBase *lb)
{
if (lb) {
BLI_freelistN(lb);
MEM_freeN(lb);
}
}
/* Check that the force field isn't disabled via its flags. */
static bool is_effector_enabled(PartDeflect *pd, bool use_rotation)
{
switch (pd->forcefield) {
case PFIELD_BOID:
case PFIELD_GUIDE:
return true;
case PFIELD_TEXTURE:
return (pd->flag & PFIELD_DO_LOCATION) != 0 && pd->tex != nullptr;
default:
if (use_rotation) {
return (pd->flag & (PFIELD_DO_LOCATION | PFIELD_DO_ROTATION)) != 0;
}
else {
return (pd->flag & PFIELD_DO_LOCATION) != 0;
}
}
}
/* Check that the force field won't have zero effect due to strength settings. */
static bool is_effector_nonzero_strength(PartDeflect *pd)
{
if (pd->f_strength != 0.0f) {
return true;
}
if (pd->forcefield == PFIELD_TEXTURE) {
return false;
}
if (pd->f_noise > 0.0f || pd->f_flow != 0.0f) {
return true;
}
switch (pd->forcefield) {
case PFIELD_BOID:
case PFIELD_GUIDE:
return true;
case PFIELD_VORTEX:
return pd->shape != PFIELD_SHAPE_POINT;
case PFIELD_DRAG:
return pd->f_damp != 0.0f;
default:
return false;
}
}
/* Check if the force field will affect its user. */
static bool is_effector_relevant(PartDeflect *pd, EffectorWeights *weights, bool use_rotation)
{
return (weights->weight[pd->forcefield] != 0.0f) && is_effector_enabled(pd, use_rotation) &&
is_effector_nonzero_strength(pd);
}
ListBase *BKE_effectors_create(Depsgraph *depsgraph,
2018-09-25 11:42:44 +10:00
Object *ob_src,
ParticleSystem *psys_src,
EffectorWeights *weights,
bool use_rotation)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
ListBase *relations = DEG_get_effector_relations(depsgraph, weights->group);
ListBase *effectors = nullptr;
if (!relations) {
return nullptr;
}
LISTBASE_FOREACH (EffectorRelation *, relation, relations) {
/* Get evaluated object. */
2018-09-25 11:42:44 +10:00
Object *ob = (Object *)DEG_get_evaluated_id(depsgraph, &relation->ob->id);
if (relation->psys) {
/* Get evaluated particle system. */
ParticleSystem *psys = static_cast<ParticleSystem *>(BLI_findstring(
&ob->particlesystem, relation->psys->name, offsetof(ParticleSystem, name)));
ParticleSettings *part = psys->part;
if (psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) {
continue;
}
PartDeflect *pd = (relation->pd == relation->psys->part->pd) ? part->pd : part->pd2;
if (!is_effector_relevant(pd, weights, use_rotation)) {
continue;
}
add_effector_evaluation(&effectors, depsgraph, scene, ob, psys, pd);
}
else {
/* Object effector. */
if (ob == ob_src) {
continue;
}
if (!is_effector_relevant(ob->pd, weights, use_rotation)) {
continue;
}
if (ob->pd->shape == PFIELD_SHAPE_POINTS && BKE_object_get_evaluated_mesh(ob) == nullptr) {
continue;
}
add_effector_evaluation(&effectors, depsgraph, scene, ob, nullptr, ob->pd);
}
}
return effectors;
}
void BKE_effectors_free(ListBase *lb)
{
if (lb) {
LISTBASE_FOREACH (EffectorCache *, eff, lb) {
if (eff->guide_data) {
MEM_freeN(eff->guide_data);
}
}
BLI_freelistN(lb);
MEM_freeN(lb);
}
}
void pd_point_from_particle(ParticleSimulationData *sim,
ParticleData *pa,
ParticleKey *state,
EffectedPoint *point)
{
ParticleSettings *part = sim->psys->part;
point->loc = state->co;
point->vel = state->vel;
point->index = pa - sim->psys->particles;
point->size = pa->size;
point->charge = 0.0f;
2018-06-17 17:05:51 +02:00
if (part->pd && part->pd->forcefield == PFIELD_CHARGE) {
point->charge += part->pd->f_strength;
}
if (part->pd2 && part->pd2->forcefield == PFIELD_CHARGE) {
point->charge += part->pd2->f_strength;
}
point->vel_to_sec = 1.0f;
point->vel_to_frame = psys_get_timestep(sim);
point->flag = 0;
if (sim->psys->part->flag & PART_ROT_DYN) {
point->ave = state->ave;
point->rot = state->rot;
}
else {
point->ave = point->rot = nullptr;
}
point->psys = sim->psys;
}
void pd_point_from_loc(Scene *scene, float *loc, float *vel, int index, EffectedPoint *point)
{
point->loc = loc;
point->vel = vel;
point->index = index;
point->size = 0.0f;
point->vel_to_sec = float(scene->r.frs_sec);
point->vel_to_frame = 1.0f;
point->flag = 0;
point->ave = point->rot = nullptr;
point->psys = nullptr;
}
void pd_point_from_soft(Scene *scene, float *loc, float *vel, int index, EffectedPoint *point)
{
point->loc = loc;
point->vel = vel;
point->index = index;
point->size = 0.0f;
point->vel_to_sec = float(scene->r.frs_sec);
point->vel_to_frame = 1.0f;
point->flag = PE_WIND_AS_SPEED;
point->ave = point->rot = nullptr;
point->psys = nullptr;
}
/************************************************/
/* Effectors */
/************************************************/
// triangle - ray callback function
static void eff_tri_ray_hit(void * /*user_data*/,
int /*index*/,
const BVHTreeRay * /*ray*/,
BVHTreeRayHit *hit)
2018-06-17 17:05:51 +02:00
{
2012-07-07 22:51:57 +00:00
/* whenever we hit a bounding box, we don't check further */
hit->dist = -1;
hit->index = 1;
}
/**
* Get visibility of a wind ray.
*/
static float eff_calc_visibility(ListBase *colliders,
EffectorCache *eff,
EffectorData *efd,
EffectedPoint *point)
The long awaited Particle patch from Janne Karhu http://www.blender3d.org/cms/New_Particle_options_a.721.0.html There's no doubt this patch had a lot of good ideas for features, and I want to compliment Janne again for getting it all to work even! A more careful review of the features and code did show however quite some flaws and bugs... partially because the current particle code was very much polluted already, but also because of the implementation lacked quality. However, the patch was too good to reject, so I've fixed and recoded the parts that needed it most. :) Here's a list of of most evident changes in the patch; - Guides support recoded. It was implemented as a true 'force field', checking all Curve path points for each particle to find the closest. Was just far too slow, and didn't support looping or bends well. The new implementation is fast (real time) and treats the paths as actual trajectory for the particle. - Guides didn't integrate in the physics/speed system either, was added as exception. Now it's integrated and can be combined with other velocities or forces - Use of Fields was slow code in general, made it use a Cache instead. - The "even" distribution didn't work for Jittered sample patterns. - The "even" or "vertexgroup" code in the main loops were badly constructed, giving too much cpu for a simple task. Instead of going over all faces many times, it now only does it once. Same part of the code used a lot of temporal unneeded mallocs. - Use of DerivedMesh or Mesh was confused, didn't work for Subsurfs in all cases - Support for vertex groups was slow, evaluating vertexgroups too often - When a vertexgroup failed to read, it was wrongly handled (set to zero). VertexGroup support now is with a name. - Split up the too huge build_particle() call in some parts (moving new code) - The "texture re-timing" option failed for moving Objects. The old code used the convention that particles were added with increasing time steps. Solved by creating a object Matrix Cache. Also: the texture coordinates had to be corrected to become "OrCo". - The "Disp" option only was used to draw less particles. Changed it to actually calculate fewer particles for 3D viewing, but render all still. So now it can be used to keep editing realtime. Removed; The "speed threshold" and "Tight" features were not copied over. This resembled too much to feature overkill. Needs re-evaluation. Also the "Deform" option was not added, I prefer to first check if the current particle system really works for the Modifier system. And: - Added integration for particle force fields in the dependency graph - Added TAB completion for vertexgroup names! - Made the 'wait cursor' only appear when particles take more than 0.5 sec - The particle jitter table order now is randomized too, giving much nicer emitting of particles in large faces. - Vortex field didn't correctly use speed/forces, so it didn't work for collisions. - Triangle distribution was wrong - Removed ancient bug that applied in a *very* weird way speed and forces. (location changes got the half force, speed the full...???) So much... might have forgotten some notes! :)
2005-11-10 16:01:56 +00:00
{
2020-06-18 12:21:38 +10:00
const int raycast_flag = BVH_RAYCAST_DEFAULT & ~BVH_RAYCAST_WATERTIGHT;
ListBase *colls = colliders;
float norm[3], len = 0.0;
float visibility = 1.0, absorption = 0.0;
2018-09-25 11:41:29 +10:00
if (!(eff->pd->flag & PFIELD_VISIBILITY)) {
return visibility;
2018-09-25 11:41:29 +10:00
}
if (!colls) {
colls = BKE_collider_cache_create(eff->depsgraph, eff->ob, nullptr);
2018-09-25 11:41:29 +10:00
}
if (!colls) {
return visibility;
2018-09-25 11:41:29 +10:00
}
negate_v3_v3(norm, efd->vec_to_point);
len = normalize_v3(norm);
2012-07-07 22:51:57 +00:00
/* check all collision objects */
LISTBASE_FOREACH (ColliderCache *, col, colls) {
CollisionModifierData *collmd = col->collmd;
2018-09-25 11:41:29 +10:00
if (col->ob == eff->ob) {
continue;
2018-09-25 11:41:29 +10:00
}
if (collmd->bvhtree) {
BVHTreeRayHit hit;
hit.index = -1;
hit.dist = len + FLT_EPSILON;
2012-07-07 22:51:57 +00:00
/* check if the way is blocked */
if (BLI_bvhtree_ray_cast_ex(collmd->bvhtree,
point->loc,
norm,
0.0f,
&hit,
eff_tri_ray_hit,
nullptr,
raycast_flag) != -1)
{
2018-09-25 11:41:29 +10:00
absorption = col->ob->pd->absorption;
2012-07-07 22:51:57 +00:00
/* visibility is only between 0 and 1, calculated from 1-absorption */
2018-09-25 11:41:29 +10:00
visibility *= CLAMPIS(1.0f - absorption, 0.0f, 1.0f);
2018-09-25 11:41:29 +10:00
if (visibility <= 0.0f) {
break;
}
}
}
}
if (!colliders) {
BKE_collider_cache_free(&colls);
}
return visibility;
}
/* Noise function for wind e.g. */
static float wind_func(RNG *rng, float strength)
{
2018-09-25 11:41:29 +10:00
int random = (BLI_rng_get_int(rng) + 1) % 128; /* max 2357 */
float force = BLI_rng_get_float(rng) + 1.0f;
float ret;
float sign = 0;
2018-06-17 17:05:51 +02:00
2018-09-25 11:41:29 +10:00
/* Dividing by 2 is not giving equal sign distribution. */
sign = (float(random) > 64.0f) ? 1.0f : -1.0f;
2018-06-17 17:05:51 +02:00
ret = sign * (float(random) / force) * strength / 128.0f;
2018-06-17 17:05:51 +02:00
return ret;
}
/* maxdist: zero effect from this distance outwards (if usemax) */
/* mindist: full effect up to this distance (if usemin) */
/* power: falloff with formula 1/r^power */
static float falloff_func(
float fac, int usemin, float mindist, int usemax, float maxdist, float power)
{
/* first quick checks */
if (usemax && fac > maxdist) {
return 0.0f;
}
if (usemin && fac < mindist) {
return 1.0f;
}
if (!usemin) {
mindist = 0.0;
}
return pow(double(1.0f + fac - mindist), double(-power));
}
static float falloff_func_dist(PartDeflect *pd, float fac)
{
2018-09-25 11:41:29 +10:00
return falloff_func(fac,
pd->flag & PFIELD_USEMIN,
pd->mindist,
pd->flag & PFIELD_USEMAX,
pd->maxdist,
pd->f_power);
}
static float falloff_func_rad(PartDeflect *pd, float fac)
{
2018-09-25 11:41:29 +10:00
return falloff_func(fac,
pd->flag & PFIELD_USEMINR,
pd->minrad,
pd->flag & PFIELD_USEMAXR,
pd->maxrad,
pd->f_power_r);
}
float effector_falloff(EffectorCache *eff,
EffectorData *efd,
EffectedPoint * /*point*/,
EffectorWeights *weights)
{
float temp[3];
float falloff = weights ? weights->weight[0] * weights->weight[eff->pd->forcefield] : 1.0f;
float fac, r_fac;
fac = dot_v3v3(efd->nor, efd->vec_to_point2);
if (eff->pd->zdir == PFIELD_Z_POS && fac < 0.0f) {
2018-09-25 11:41:29 +10:00
falloff = 0.0f;
}
else if (eff->pd->zdir == PFIELD_Z_NEG && fac > 0.0f) {
2018-09-25 11:41:29 +10:00
falloff = 0.0f;
}
else {
switch (eff->pd->falloff) {
2018-04-16 17:08:27 +02:00
case PFIELD_FALL_SPHERE:
2018-09-25 11:41:29 +10:00
falloff *= falloff_func_dist(eff->pd, efd->distance);
break;
2018-04-16 17:08:27 +02:00
case PFIELD_FALL_TUBE:
falloff *= falloff_func_dist(eff->pd, fabsf(fac));
if (falloff == 0.0f) {
2018-04-16 17:08:27 +02:00
break;
}
2018-04-16 17:08:27 +02:00
madd_v3_v3v3fl(temp, efd->vec_to_point2, efd->nor, -fac);
2018-09-25 11:41:29 +10:00
r_fac = len_v3(temp);
falloff *= falloff_func_rad(eff->pd, r_fac);
break;
2018-04-16 17:08:27 +02:00
case PFIELD_FALL_CONE:
falloff *= falloff_func_dist(eff->pd, fabsf(fac));
if (falloff == 0.0f) {
2018-04-16 17:08:27 +02:00
break;
}
2018-09-25 11:42:44 +10:00
r_fac = RAD2DEGF(saacos(fac / len_v3(efd->vec_to_point2)));
2018-09-25 11:41:29 +10:00
falloff *= falloff_func_rad(eff->pd, r_fac);
2018-04-16 17:08:27 +02:00
break;
}
}
return falloff;
}
2021-12-07 18:14:39 +11:00
bool closest_point_on_surface(SurfaceModifierData *surmd,
const float co[3],
float surface_co[3],
float surface_nor[3],
float surface_vel[3])
{
BVHTreeFromMesh *bvhtree = surmd->runtime.bvhtree;
BVHTreeNearest nearest;
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
BLI_bvhtree_find_nearest(bvhtree->tree, co, &nearest, bvhtree->nearest_callback, bvhtree);
if (nearest.index != -1) {
copy_v3_v3(surface_co, nearest.co);
if (surface_nor) {
copy_v3_v3(surface_nor, nearest.no);
}
if (surface_vel) {
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
const int *corner_verts = bvhtree->corner_verts;
const MLoopTri *lt = &bvhtree->looptri[nearest.index];
2018-06-17 17:05:51 +02:00
Mesh: Replace MLoop struct with generic attributes Implements #102359. Split the `MLoop` struct into two separate integer arrays called `corner_verts` and `corner_edges`, referring to the vertex each corner is attached to and the next edge around the face at each corner. These arrays can be sliced to give access to the edges or vertices in a face. Then they are often referred to as "poly_verts" or "poly_edges". The main benefits are halving the necessary memory bandwidth when only one array is used and simplifications from using regular integer indices instead of a special-purpose struct. The commit also starts a renaming from "loop" to "corner" in mesh code. Like the other mesh struct of array refactors, forward compatibility is kept by writing files with the older format. This will be done until 4.0 to ease the transition process. Looking at a small portion of the patch should give a good impression for the rest of the changes. I tried to make the changes as small as possible so it's easy to tell the correctness from the diff. Though I found Blender developers have been very inventive over the last decade when finding different ways to loop over the corners in a face. For performance, nearly every piece of code that deals with `Mesh` is slightly impacted. Any algorithm that is memory bottle-necked should see an improvement. For example, here is a comparison of interpolating a vertex float attribute to face corners (Ryzen 3700x): **Before** (Average: 3.7 ms, Min: 3.4 ms) ``` threading::parallel_for(loops.index_range(), 4096, [&](IndexRange range) { for (const int64_t i : range) { dst[i] = src[loops[i].v]; } }); ``` **After** (Average: 2.9 ms, Min: 2.6 ms) ``` array_utils::gather(src, corner_verts, dst); ``` That's an improvement of 28% to the average timings, and it's also a simplification, since an index-based routine can be used instead. For more examples using the new arrays, see the design task. Pull Request: https://projects.blender.org/blender/blender/pulls/104424
2023-03-20 15:55:13 +01:00
copy_v3_v3(surface_vel, surmd->runtime.vert_velocities[corner_verts[lt->tri[0]]]);
add_v3_v3(surface_vel, surmd->runtime.vert_velocities[corner_verts[lt->tri[1]]]);
add_v3_v3(surface_vel, surmd->runtime.vert_velocities[corner_verts[lt->tri[2]]]);
mul_v3_fl(surface_vel, (1.0f / 3.0f));
}
2021-12-07 18:14:39 +11:00
return true;
}
The long awaited Particle patch from Janne Karhu http://www.blender3d.org/cms/New_Particle_options_a.721.0.html There's no doubt this patch had a lot of good ideas for features, and I want to compliment Janne again for getting it all to work even! A more careful review of the features and code did show however quite some flaws and bugs... partially because the current particle code was very much polluted already, but also because of the implementation lacked quality. However, the patch was too good to reject, so I've fixed and recoded the parts that needed it most. :) Here's a list of of most evident changes in the patch; - Guides support recoded. It was implemented as a true 'force field', checking all Curve path points for each particle to find the closest. Was just far too slow, and didn't support looping or bends well. The new implementation is fast (real time) and treats the paths as actual trajectory for the particle. - Guides didn't integrate in the physics/speed system either, was added as exception. Now it's integrated and can be combined with other velocities or forces - Use of Fields was slow code in general, made it use a Cache instead. - The "even" distribution didn't work for Jittered sample patterns. - The "even" or "vertexgroup" code in the main loops were badly constructed, giving too much cpu for a simple task. Instead of going over all faces many times, it now only does it once. Same part of the code used a lot of temporal unneeded mallocs. - Use of DerivedMesh or Mesh was confused, didn't work for Subsurfs in all cases - Support for vertex groups was slow, evaluating vertexgroups too often - When a vertexgroup failed to read, it was wrongly handled (set to zero). VertexGroup support now is with a name. - Split up the too huge build_particle() call in some parts (moving new code) - The "texture re-timing" option failed for moving Objects. The old code used the convention that particles were added with increasing time steps. Solved by creating a object Matrix Cache. Also: the texture coordinates had to be corrected to become "OrCo". - The "Disp" option only was used to draw less particles. Changed it to actually calculate fewer particles for 3D viewing, but render all still. So now it can be used to keep editing realtime. Removed; The "speed threshold" and "Tight" features were not copied over. This resembled too much to feature overkill. Needs re-evaluation. Also the "Deform" option was not added, I prefer to first check if the current particle system really works for the Modifier system. And: - Added integration for particle force fields in the dependency graph - Added TAB completion for vertexgroup names! - Made the 'wait cursor' only appear when particles take more than 0.5 sec - The particle jitter table order now is randomized too, giving much nicer emitting of particles in large faces. - Vortex field didn't correctly use speed/forces, so it didn't work for collisions. - Triangle distribution was wrong - Removed ancient bug that applied in a *very* weird way speed and forces. (location changes got the half force, speed the full...???) So much... might have forgotten some notes! :)
2005-11-10 16:01:56 +00:00
2021-12-07 18:14:39 +11:00
return false;
}
2021-12-07 18:14:39 +11:00
bool get_effector_data(EffectorCache *eff,
EffectorData *efd,
EffectedPoint *point,
int real_velocity)
{
float cfra = DEG_get_ctime(eff->depsgraph);
2021-12-07 18:14:39 +11:00
bool ret = false;
/* In case surface object is in Edit mode when loading the .blend,
* surface modifier is never executed and bvhtree never built, see #48415. */
if (eff->pd && eff->pd->shape == PFIELD_SHAPE_SURFACE && eff->surmd &&
eff->surmd->runtime.bvhtree) {
/* closest point in the object surface is an effector */
float vec[3];
/* using velocity corrected location allows for easier sliding over effector surface */
copy_v3_v3(vec, point->vel);
mul_v3_fl(vec, point->vel_to_frame);
add_v3_v3(vec, point->loc);
ret = closest_point_on_surface(
eff->surmd, vec, efd->loc, efd->nor, real_velocity ? efd->vel : nullptr);
efd->size = 0.0f;
}
2018-09-25 11:41:29 +10:00
else if (eff->pd && eff->pd->shape == PFIELD_SHAPE_POINTS) {
/* TODO: hair and points object support */
const Mesh *me_eval = BKE_object_get_evaluated_mesh(eff->ob);
const blender::Span<blender::float3> positions = me_eval->vert_positions();
const blender::Span<blender::float3> vert_normals = me_eval->vert_normals();
if (me_eval != nullptr) {
Mesh: Move positions to a generic attribute **Changes** As described in T93602, this patch removes all use of the `MVert` struct, replacing it with a generic named attribute with the name `"position"`, consistent with other geometry types. Variable names have been changed from `verts` to `positions`, to align with the attribute name and the more generic design (positions are not vertices, they are just an attribute stored on the point domain). This change is made possible by previous commits that moved all other data out of `MVert` to runtime data or other generic attributes. What remains is mostly a simple type change. Though, the type still shows up 859 times, so the patch is quite large. One compromise is that now `CD_MASK_BAREMESH` now contains `CD_PROP_FLOAT3`. With the general move towards generic attributes over custom data types, we are removing use of these type masks anyway. **Benefits** The most obvious benefit is reduced memory usage and the benefits that brings in memory-bound situations. `float3` is only 3 bytes, in comparison to `MVert` which was 4. When there are millions of vertices this starts to matter more. The other benefits come from using a more generic type. Instead of writing algorithms specifically for `MVert`, code can just use arrays of vectors. This will allow eliminating many temporary arrays or wrappers used to extract positions. Many possible improvements aren't implemented in this patch, though I did switch simplify or remove the process of creating temporary position arrays in a few places. The design clarity that "positions are just another attribute" brings allows removing explicit copying of vertices in some procedural operations-- they are just processed like most other attributes. **Performance** This touches so many areas that it's hard to benchmark exhaustively, but I observed some areas as examples. * The mesh line node with 4 million count was 1.5x (8ms to 12ms) faster. * The Spring splash screen went from ~4.3 to ~4.5 fps. * The subdivision surface modifier/node was slightly faster RNA access through Python may be slightly slower, since now we need a name lookup instead of just a custom data type lookup for each index. **Future Improvements** * Remove uses of "vert_coords" functions: * `BKE_mesh_vert_coords_alloc` * `BKE_mesh_vert_coords_get` * `BKE_mesh_vert_coords_apply{_with_mat4}` * Remove more hidden copying of positions * General simplification now possible in many areas * Convert more code to C++ to use `float3` instead of `float[3]` * Currently `reinterpret_cast` is used for those C-API functions Differential Revision: https://developer.blender.org/D15982
2023-01-10 00:10:43 -05:00
copy_v3_v3(efd->loc, positions[*efd->index]);
Refactor: Move normals out of MVert, lazy calculation As described in T91186, this commit moves mesh vertex normals into a contiguous array of float vectors in a custom data layer, how face normals are currently stored. The main interface is documented in `BKE_mesh.h`. Vertex and face normals are now calculated on-demand and cached, retrieved with an "ensure" function. Since the logical state of a mesh is now "has normals when necessary", they can be retrieved from a `const` mesh. The goal is to use on-demand calculation for all derived data, but leave room for eager calculation for performance purposes (modifier evaluation is threaded, but viewport data generation is not). **Benefits** This moves us closer to a SoA approach rather than the current AoS paradigm. Accessing a contiguous `float3` is much more efficient than retrieving data from a larger struct. The memory requirements for accessing only normals or vertex locations are smaller, and at the cost of more memory usage for just normals, they now don't have to be converted between float and short, which also simplifies code In the future, the remaining items can be removed from `MVert`, leaving only `float3`, which has similar benefits (see T93602). Removing the combination of derived and original data makes it conceptually simpler to only calculate normals when necessary. This is especially important now that we have more opportunities for temporary meshes in geometry nodes. **Performance** In addition to the theoretical future performance improvements by making `MVert == float3`, I've done some basic performance testing on this patch directly. The data is fairly rough, but it gives an idea about where things stand generally. - Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms), showing that accessing just `MVert` is now more efficient. - Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight change that at least shows there is no regression. - Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small but observable speedup. - Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms), shows that using normals in geometry nodes is faster. - Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms), shows that calculating normals is slightly faster now. - File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB), Normals are not saved in files, which can help with large meshes. As for memory usage, it may be slightly more in some cases, but I didn't observe any difference in the production files I tested. **Tests** Some modifiers and cycles test results need to be updated with this commit, for two reasons: - The subdivision surface modifier is not responsible for calculating normals anymore. In master, the modifier creates different normals than the result of the `Mesh` normal calculation, so this is a bug fix. - There are small differences in the results of some modifiers that use normals because they are not converted to and from `short` anymore. **Future improvements** - Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier already retrieves normals if they are needed anyway. - Copy normals as part of a better CoW system for attributes. - Make more areas use lazy instead of eager normal calculation. - Remove `BKE_mesh_normals_tag_dirty` in more places since that is now the default state of a new mesh. - Possibly apply a similar change to derived face corner normals. Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
copy_v3_v3(efd->nor, vert_normals[*efd->index]);
mul_m4_v3(eff->ob->object_to_world, efd->loc);
mul_mat3_m4_v3(eff->ob->object_to_world, efd->nor);
normalize_v3(efd->nor);
efd->size = 0.0f;
2021-12-07 18:14:39 +11:00
ret = true;
}
}
else if (eff->psys) {
ParticleData *pa = eff->psys->particles + *efd->index;
ParticleKey state;
/* exclude the particle itself for self effecting particles */
if (eff->psys == point->psys && *efd->index == point->index) {
/* pass */
}
else {
ParticleSimulationData sim = {nullptr};
sim.depsgraph = eff->depsgraph;
2018-09-25 11:41:29 +10:00
sim.scene = eff->scene;
sim.ob = eff->ob;
sim.psys = eff->psys;
/* TODO: time from actual previous calculated frame (step might not be 1) */
state.time = cfra - 1.0f;
ret = psys_get_particle_state(&sim, *efd->index, &state, false);
/* TODO */
// if (eff->pd->forcefiled == PFIELD_HARMONIC && ret==0) {
// if (pa->dietime < eff->psys->cfra)
// eff->flag |= PE_VELOCITY_TO_IMPULSE;
//}
copy_v3_v3(efd->loc, state.co);
/* rather than use the velocity use rotated x-axis (defaults to velocity) */
efd->nor[0] = 1.0f;
efd->nor[1] = efd->nor[2] = 0.0f;
mul_qt_v3(state.rot, efd->nor);
2018-09-25 11:41:29 +10:00
if (real_velocity) {
copy_v3_v3(efd->vel, state.vel);
2018-09-25 11:41:29 +10:00
}
efd->size = pa->size;
}
}
else {
/* use center of object for distance calculus */
const Object *ob = eff->ob;
/* Use z-axis as normal. */
normalize_v3_v3(efd->nor, ob->object_to_world[2]);
if (eff->pd && ELEM(eff->pd->shape, PFIELD_SHAPE_PLANE, PFIELD_SHAPE_LINE)) {
float temp[3], translate[3];
sub_v3_v3v3(temp, point->loc, ob->object_to_world[3]);
project_v3_v3v3(translate, temp, efd->nor);
/* for vortex the shape chooses between old / new force */
2018-09-25 11:42:44 +10:00
if (eff->pd->forcefield == PFIELD_VORTEX || eff->pd->shape == PFIELD_SHAPE_LINE) {
add_v3_v3v3(efd->loc, ob->object_to_world[3], translate);
2018-09-25 11:41:29 +10:00
}
2023-02-10 11:34:20 +11:00
else { /* Normally `efd->loc` is closest point on effector XY-plane. */
sub_v3_v3v3(efd->loc, point->loc, translate);
2018-09-25 11:41:29 +10:00
}
}
else {
copy_v3_v3(efd->loc, ob->object_to_world[3]);
}
zero_v3(efd->vel);
efd->size = 0.0f;
2021-12-07 18:14:39 +11:00
ret = true;
}
if (ret) {
sub_v3_v3v3(efd->vec_to_point, point->loc, efd->loc);
efd->distance = len_v3(efd->vec_to_point);
/* Rest length for harmonic effector,
* will have to see later if this could be extended to other effectors. */
if (eff->pd && eff->pd->forcefield == PFIELD_HARMONIC && eff->pd->f_size) {
2018-09-25 11:41:29 +10:00
mul_v3_fl(efd->vec_to_point, (efd->distance - eff->pd->f_size) / efd->distance);
}
if (eff->flag & PE_USE_NORMAL_DATA) {
copy_v3_v3(efd->vec_to_point2, efd->vec_to_point);
copy_v3_v3(efd->nor2, efd->nor);
}
else {
/* for some effectors we need the object center every time */
sub_v3_v3v3(efd->vec_to_point2, point->loc, eff->ob->object_to_world[3]);
normalize_v3_v3(efd->nor2, eff->ob->object_to_world[2]);
}
}
return ret;
}
static void get_effector_tot(
EffectorCache *eff, EffectorData *efd, EffectedPoint *point, int *tot, int *p, int *step)
{
*p = 0;
efd->index = p;
if (eff->pd->shape == PFIELD_SHAPE_POINTS) {
/* TODO: hair and points object support */
const Mesh *me_eval = BKE_object_get_evaluated_mesh(eff->ob);
*tot = me_eval != nullptr ? me_eval->totvert : 1;
if (*tot && eff->pd->forcefield == PFIELD_HARMONIC && point->index >= 0) {
*p = point->index % *tot;
2018-09-25 11:41:29 +10:00
*tot = *p + 1;
}
}
else if (eff->psys) {
*tot = eff->psys->totpart;
if (eff->pd->forcefield == PFIELD_CHARGE) {
2018-06-17 17:05:51 +02:00
/* Only the charge of the effected particle is used for
* interaction, not fall-offs. If the fall-offs aren't the
* same this will be nonphysical, but for animation this
* could be the wanted behavior. If you want physical
* correctness the fall-off should be spherical 2.0 anyways.
*/
efd->charge = eff->pd->f_strength;
}
2018-09-25 11:41:29 +10:00
else if (eff->pd->forcefield == PFIELD_HARMONIC &&
(eff->pd->flag & PFIELD_MULTIPLE_SPRINGS) == 0) {
/* every particle is mapped to only one harmonic effector particle */
2018-09-25 11:41:29 +10:00
*p = point->index % eff->psys->totpart;
*tot = *p + 1;
}
if (eff->psys->part->effector_amount) {
int totpart = eff->psys->totpart;
int amount = eff->psys->part->effector_amount;
*step = (totpart > amount) ? int(ceil(float(totpart) / float(amount))) : 1;
}
}
else {
*tot = 1;
}
}
static void do_texture_effector(EffectorCache *eff,
EffectorData *efd,
EffectedPoint *point,
float *total_force)
{
TexResult result[4];
float tex_co[3], strength, force[3];
float nabla = eff->pd->tex_nabla;
int hasrgb;
short mode = eff->pd->tex_mode;
if (!eff->pd->tex) {
return;
}
2018-09-25 11:41:29 +10:00
strength = eff->pd->f_strength * efd->falloff;
2012-04-29 15:47:02 +00:00
copy_v3_v3(tex_co, point->loc);
if (eff->pd->flag & PFIELD_TEX_OBJECT) {
mul_m4_v3(eff->ob->world_to_object, tex_co);
if (eff->pd->flag & PFIELD_TEX_2D) {
tex_co[2] = 0.0f;
}
}
else if (eff->pd->flag & PFIELD_TEX_2D) {
2018-09-25 11:41:29 +10:00
float fac = -dot_v3v3(tex_co, efd->nor);
madd_v3_v3fl(tex_co, efd->nor, fac);
}
hasrgb = multitex_ext(
eff->pd->tex, tex_co, nullptr, nullptr, 0, result, 0, nullptr, true, false);
2018-09-25 11:41:29 +10:00
if (hasrgb && mode == PFIELD_TEX_RGB) {
2022-01-28 13:28:31 +01:00
force[0] = (0.5f - result->trgba[0]) * strength;
force[1] = (0.5f - result->trgba[1]) * strength;
force[2] = (0.5f - result->trgba[2]) * strength;
}
else if (nabla != 0) {
2018-09-25 11:41:29 +10:00
strength /= nabla;
tex_co[0] += nabla;
multitex_ext(eff->pd->tex, tex_co, nullptr, nullptr, 0, result + 1, 0, nullptr, true, false);
tex_co[0] -= nabla;
tex_co[1] += nabla;
multitex_ext(eff->pd->tex, tex_co, nullptr, nullptr, 0, result + 2, 0, nullptr, true, false);
tex_co[1] -= nabla;
tex_co[2] += nabla;
multitex_ext(eff->pd->tex, tex_co, nullptr, nullptr, 0, result + 3, 0, nullptr, true, false);
if (mode == PFIELD_TEX_GRAD || !hasrgb) { /* if we don't have rgb fall back to grad */
/* generate intensity if texture only has rgb value */
if (hasrgb & TEX_RGB) {
2018-09-25 11:41:29 +10:00
for (int i = 0; i < 4; i++) {
2022-01-28 13:28:31 +01:00
result[i].tin = (1.0f / 3.0f) *
(result[i].trgba[0] + result[i].trgba[1] + result[i].trgba[2]);
}
}
force[0] = (result[0].tin - result[1].tin) * strength;
force[1] = (result[0].tin - result[2].tin) * strength;
force[2] = (result[0].tin - result[3].tin) * strength;
}
else { /*PFIELD_TEX_CURL*/
float dbdy, dgdz, drdz, dbdx, dgdx, drdy;
2022-01-28 13:28:31 +01:00
dbdy = result[2].trgba[2] - result[0].trgba[2];
dgdz = result[3].trgba[1] - result[0].trgba[1];
drdz = result[3].trgba[0] - result[0].trgba[0];
dbdx = result[1].trgba[2] - result[0].trgba[2];
dgdx = result[1].trgba[1] - result[0].trgba[1];
drdy = result[2].trgba[0] - result[0].trgba[0];
force[0] = (dbdy - dgdz) * strength;
force[1] = (drdz - dbdx) * strength;
force[2] = (dgdx - drdy) * strength;
}
}
else {
zero_v3(force);
}
if (eff->pd->flag & PFIELD_TEX_2D) {
float fac = -dot_v3v3(force, efd->nor);
madd_v3_v3fl(force, efd->nor, fac);
}
if (eff->pd->flag & PFIELD_DO_LOCATION) {
add_v3_v3(total_force, force);
}
}
static void do_physical_effector(EffectorCache *eff,
EffectorData *efd,
EffectedPoint *point,
float *total_force)
{
PartDeflect *pd = eff->pd;
RNG *rng = pd->rng;
2012-10-22 08:15:51 +00:00
float force[3] = {0, 0, 0};
float temp[3];
float fac;
float strength = pd->f_strength;
float damp = pd->f_damp;
float noise_factor = pd->f_noise;
float flow_falloff = efd->falloff;
if (noise_factor > 0.0f) {
strength += wind_func(rng, noise_factor);
2018-09-25 11:41:29 +10:00
if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG)) {
damp += wind_func(rng, noise_factor);
2018-09-25 11:41:29 +10:00
}
}
copy_v3_v3(force, efd->vec_to_point);
switch (pd->forcefield) {
case PFIELD_WIND:
copy_v3_v3(force, efd->nor);
mul_v3_fl(force, strength * efd->falloff);
break;
case PFIELD_FORCE:
normalize_v3(force);
2018-09-25 11:41:29 +10:00
if (pd->flag & PFIELD_GRAVITATION) { /* Option: Multiply by 1/distance^2 */
if (efd->distance < FLT_EPSILON) {
strength = 0.0f;
}
else {
strength *= powf(efd->distance, -2.0f);
}
}
mul_v3_fl(force, strength * efd->falloff);
break;
case PFIELD_VORTEX:
/* old vortex force */
if (pd->shape == PFIELD_SHAPE_POINT) {
cross_v3_v3v3(force, efd->nor, efd->vec_to_point);
normalize_v3(force);
mul_v3_fl(force, strength * efd->distance * efd->falloff);
}
else {
/* new vortex force */
cross_v3_v3v3(temp, efd->nor2, efd->vec_to_point2);
mul_v3_fl(temp, strength * efd->falloff);
cross_v3_v3v3(force, efd->nor2, temp);
mul_v3_fl(force, strength * efd->falloff);
madd_v3_v3fl(temp, point->vel, -point->vel_to_sec);
add_v3_v3(force, temp);
The long awaited Particle patch from Janne Karhu http://www.blender3d.org/cms/New_Particle_options_a.721.0.html There's no doubt this patch had a lot of good ideas for features, and I want to compliment Janne again for getting it all to work even! A more careful review of the features and code did show however quite some flaws and bugs... partially because the current particle code was very much polluted already, but also because of the implementation lacked quality. However, the patch was too good to reject, so I've fixed and recoded the parts that needed it most. :) Here's a list of of most evident changes in the patch; - Guides support recoded. It was implemented as a true 'force field', checking all Curve path points for each particle to find the closest. Was just far too slow, and didn't support looping or bends well. The new implementation is fast (real time) and treats the paths as actual trajectory for the particle. - Guides didn't integrate in the physics/speed system either, was added as exception. Now it's integrated and can be combined with other velocities or forces - Use of Fields was slow code in general, made it use a Cache instead. - The "even" distribution didn't work for Jittered sample patterns. - The "even" or "vertexgroup" code in the main loops were badly constructed, giving too much cpu for a simple task. Instead of going over all faces many times, it now only does it once. Same part of the code used a lot of temporal unneeded mallocs. - Use of DerivedMesh or Mesh was confused, didn't work for Subsurfs in all cases - Support for vertex groups was slow, evaluating vertexgroups too often - When a vertexgroup failed to read, it was wrongly handled (set to zero). VertexGroup support now is with a name. - Split up the too huge build_particle() call in some parts (moving new code) - The "texture re-timing" option failed for moving Objects. The old code used the convention that particles were added with increasing time steps. Solved by creating a object Matrix Cache. Also: the texture coordinates had to be corrected to become "OrCo". - The "Disp" option only was used to draw less particles. Changed it to actually calculate fewer particles for 3D viewing, but render all still. So now it can be used to keep editing realtime. Removed; The "speed threshold" and "Tight" features were not copied over. This resembled too much to feature overkill. Needs re-evaluation. Also the "Deform" option was not added, I prefer to first check if the current particle system really works for the Modifier system. And: - Added integration for particle force fields in the dependency graph - Added TAB completion for vertexgroup names! - Made the 'wait cursor' only appear when particles take more than 0.5 sec - The particle jitter table order now is randomized too, giving much nicer emitting of particles in large faces. - Vortex field didn't correctly use speed/forces, so it didn't work for collisions. - Triangle distribution was wrong - Removed ancient bug that applied in a *very* weird way speed and forces. (location changes got the half force, speed the full...???) So much... might have forgotten some notes! :)
2005-11-10 16:01:56 +00:00
}
break;
case PFIELD_MAGNET:
if (ELEM(eff->pd->shape, PFIELD_SHAPE_POINT, PFIELD_SHAPE_LINE)) {
/* magnetic field of a moving charge */
cross_v3_v3v3(temp, efd->nor, efd->vec_to_point);
}
else {
copy_v3_v3(temp, efd->nor);
}
normalize_v3(temp);
mul_v3_fl(temp, strength * efd->falloff);
cross_v3_v3v3(force, point->vel, temp);
mul_v3_fl(force, point->vel_to_sec);
break;
case PFIELD_HARMONIC:
mul_v3_fl(force, -strength * efd->falloff);
copy_v3_v3(temp, point->vel);
mul_v3_fl(temp, -damp * 2.0f * sqrtf(fabsf(strength)) * point->vel_to_sec);
add_v3_v3(force, temp);
break;
case PFIELD_CHARGE:
mul_v3_fl(force, point->charge * strength * efd->falloff);
break;
case PFIELD_LENNARDJ:
fac = pow((efd->size + point->size) / efd->distance, 6.0);
2018-09-25 11:41:29 +10:00
fac = -fac * (1.0f - fac) / efd->distance;
/* limit the repulsive term drastically to avoid huge forces */
2018-09-25 11:41:29 +10:00
fac = ((fac > 2.0f) ? 2.0f : fac);
mul_v3_fl(force, strength * fac);
break;
Initial code for boids v2 Too many new features to list! But here are the biggies: - Boids can move on air and/or land, or climb a goal object. - Proper interaction with collision objects. * Closest collision object in negative z direction is considered as ground. * Other collision objects are obstacles and boids collide with them. - Boid behavior rules are now added to a dynamic list. * Many new rules and many still not implemented. * Different rule evaluation modes (fuzzy, random, average). - Only particle systems defined by per system "boid relations" are considered for simulation of that system. * This is in addition to the boids own system of course. * Relations define other systems as "neutral", "friend" or "enemy". - All effectors now effect boid physics, not boid brains. * This allows forcing boids somewhere. * Exception to this is new "boid" effector, which defines boid predators (positive strength) and goals (negative strength). Known issue: - Boid health isn't yet stored in pointcache so simulations with "fight" rule are not be read from cache properly. - Object/Group visualization object's animation is not played in "particle time". This is definately the wanted behavior, but isn't possible with the current state of dupliobject code. Other new features: - Particle systems can now be named separately from particle settings. * Default name for particle settings is now "ParticleSettings" instead of "PSys" - Per particle system list of particle effector weights. * Enables different effection strengths for particles from different particle systems with without messing around with effector group setting. Other code changes: - KDTree now supports range search as it's needed for new boids. - "Keyed particle targets" renamed as general "particle targets", as they're needed for boids too. (this might break some files saved with new keyed particles) Bug fixes: - Object & group visualizations didn't work. - Interpolating pointcache didn't do rotation.
2009-07-20 23:52:53 +00:00
case PFIELD_BOID:
/* Boid field is handled completely in boids code. */
return;
case PFIELD_TURBULENCE:
if (pd->flag & PFIELD_GLOBAL_CO) {
copy_v3_v3(temp, point->loc);
}
else {
add_v3_v3v3(temp, efd->vec_to_point2, efd->nor2);
}
force[0] = -1.0f + 2.0f * BLI_noise_generic_turbulence(
pd->f_size, temp[0], temp[1], temp[2], 2, false, 2);
force[1] = -1.0f + 2.0f * BLI_noise_generic_turbulence(
pd->f_size, temp[1], temp[2], temp[0], 2, false, 2);
force[2] = -1.0f + 2.0f * BLI_noise_generic_turbulence(
pd->f_size, temp[2], temp[0], temp[1], 2, false, 2);
mul_v3_fl(force, strength * efd->falloff);
break;
case PFIELD_DRAG:
copy_v3_v3(force, point->vel);
fac = normalize_v3(force) * point->vel_to_sec;
strength = MIN2(strength, 2.0f);
damp = MIN2(damp, 2.0f);
mul_v3_fl(force, -efd->falloff * fac * (strength * fac + damp));
Initial code for boids v2 Too many new features to list! But here are the biggies: - Boids can move on air and/or land, or climb a goal object. - Proper interaction with collision objects. * Closest collision object in negative z direction is considered as ground. * Other collision objects are obstacles and boids collide with them. - Boid behavior rules are now added to a dynamic list. * Many new rules and many still not implemented. * Different rule evaluation modes (fuzzy, random, average). - Only particle systems defined by per system "boid relations" are considered for simulation of that system. * This is in addition to the boids own system of course. * Relations define other systems as "neutral", "friend" or "enemy". - All effectors now effect boid physics, not boid brains. * This allows forcing boids somewhere. * Exception to this is new "boid" effector, which defines boid predators (positive strength) and goals (negative strength). Known issue: - Boid health isn't yet stored in pointcache so simulations with "fight" rule are not be read from cache properly. - Object/Group visualization object's animation is not played in "particle time". This is definately the wanted behavior, but isn't possible with the current state of dupliobject code. Other new features: - Particle systems can now be named separately from particle settings. * Default name for particle settings is now "ParticleSettings" instead of "PSys" - Per particle system list of particle effector weights. * Enables different effection strengths for particles from different particle systems with without messing around with effector group setting. Other code changes: - KDTree now supports range search as it's needed for new boids. - "Keyed particle targets" renamed as general "particle targets", as they're needed for boids too. (this might break some files saved with new keyed particles) Bug fixes: - Object & group visualizations didn't work. - Interpolating pointcache didn't do rotation.
2009-07-20 23:52:53 +00:00
break;
case PFIELD_FLUIDFLOW:
zero_v3(force);
flow_falloff = 0;
2019-12-17 08:38:08 +11:00
#ifdef WITH_FLUID
if (pd->f_source) {
float density;
if ((density = BKE_fluid_get_velocity_at(pd->f_source, point->loc, force)) >= 0.0f) {
float influence = strength * efd->falloff;
2018-09-25 11:41:29 +10:00
if (pd->flag & PFIELD_SMOKE_DENSITY) {
influence *= density;
2018-09-25 11:41:29 +10:00
}
mul_v3_fl(force, influence);
flow_falloff = influence;
}
}
2019-12-17 08:38:08 +11:00
#endif
break;
The long awaited Particle patch from Janne Karhu http://www.blender3d.org/cms/New_Particle_options_a.721.0.html There's no doubt this patch had a lot of good ideas for features, and I want to compliment Janne again for getting it all to work even! A more careful review of the features and code did show however quite some flaws and bugs... partially because the current particle code was very much polluted already, but also because of the implementation lacked quality. However, the patch was too good to reject, so I've fixed and recoded the parts that needed it most. :) Here's a list of of most evident changes in the patch; - Guides support recoded. It was implemented as a true 'force field', checking all Curve path points for each particle to find the closest. Was just far too slow, and didn't support looping or bends well. The new implementation is fast (real time) and treats the paths as actual trajectory for the particle. - Guides didn't integrate in the physics/speed system either, was added as exception. Now it's integrated and can be combined with other velocities or forces - Use of Fields was slow code in general, made it use a Cache instead. - The "even" distribution didn't work for Jittered sample patterns. - The "even" or "vertexgroup" code in the main loops were badly constructed, giving too much cpu for a simple task. Instead of going over all faces many times, it now only does it once. Same part of the code used a lot of temporal unneeded mallocs. - Use of DerivedMesh or Mesh was confused, didn't work for Subsurfs in all cases - Support for vertex groups was slow, evaluating vertexgroups too often - When a vertexgroup failed to read, it was wrongly handled (set to zero). VertexGroup support now is with a name. - Split up the too huge build_particle() call in some parts (moving new code) - The "texture re-timing" option failed for moving Objects. The old code used the convention that particles were added with increasing time steps. Solved by creating a object Matrix Cache. Also: the texture coordinates had to be corrected to become "OrCo". - The "Disp" option only was used to draw less particles. Changed it to actually calculate fewer particles for 3D viewing, but render all still. So now it can be used to keep editing realtime. Removed; The "speed threshold" and "Tight" features were not copied over. This resembled too much to feature overkill. Needs re-evaluation. Also the "Deform" option was not added, I prefer to first check if the current particle system really works for the Modifier system. And: - Added integration for particle force fields in the dependency graph - Added TAB completion for vertexgroup names! - Made the 'wait cursor' only appear when particles take more than 0.5 sec - The particle jitter table order now is randomized too, giving much nicer emitting of particles in large faces. - Vortex field didn't correctly use speed/forces, so it didn't work for collisions. - Triangle distribution was wrong - Removed ancient bug that applied in a *very* weird way speed and forces. (location changes got the half force, speed the full...???) So much... might have forgotten some notes! :)
2005-11-10 16:01:56 +00:00
}
if (pd->flag & PFIELD_DO_LOCATION) {
2018-09-25 11:41:29 +10:00
madd_v3_v3fl(total_force, force, 1.0f / point->vel_to_sec);
if (!ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG) && pd->f_flow != 0.0f) {
madd_v3_v3fl(total_force, point->vel, -pd->f_flow * flow_falloff);
}
}
if (pd->flag & PFIELD_DO_ROTATION && point->ave && point->rot) {
float xvec[3] = {1.0f, 0.0f, 0.0f};
float dave[3];
mul_qt_v3(point->rot, xvec);
cross_v3_v3v3(dave, xvec, force);
if (pd->f_flow != 0.0f) {
madd_v3_v3fl(dave, point->ave, -pd->f_flow * efd->falloff);
}
add_v3_v3(point->ave, dave);
}
The long awaited Particle patch from Janne Karhu http://www.blender3d.org/cms/New_Particle_options_a.721.0.html There's no doubt this patch had a lot of good ideas for features, and I want to compliment Janne again for getting it all to work even! A more careful review of the features and code did show however quite some flaws and bugs... partially because the current particle code was very much polluted already, but also because of the implementation lacked quality. However, the patch was too good to reject, so I've fixed and recoded the parts that needed it most. :) Here's a list of of most evident changes in the patch; - Guides support recoded. It was implemented as a true 'force field', checking all Curve path points for each particle to find the closest. Was just far too slow, and didn't support looping or bends well. The new implementation is fast (real time) and treats the paths as actual trajectory for the particle. - Guides didn't integrate in the physics/speed system either, was added as exception. Now it's integrated and can be combined with other velocities or forces - Use of Fields was slow code in general, made it use a Cache instead. - The "even" distribution didn't work for Jittered sample patterns. - The "even" or "vertexgroup" code in the main loops were badly constructed, giving too much cpu for a simple task. Instead of going over all faces many times, it now only does it once. Same part of the code used a lot of temporal unneeded mallocs. - Use of DerivedMesh or Mesh was confused, didn't work for Subsurfs in all cases - Support for vertex groups was slow, evaluating vertexgroups too often - When a vertexgroup failed to read, it was wrongly handled (set to zero). VertexGroup support now is with a name. - Split up the too huge build_particle() call in some parts (moving new code) - The "texture re-timing" option failed for moving Objects. The old code used the convention that particles were added with increasing time steps. Solved by creating a object Matrix Cache. Also: the texture coordinates had to be corrected to become "OrCo". - The "Disp" option only was used to draw less particles. Changed it to actually calculate fewer particles for 3D viewing, but render all still. So now it can be used to keep editing realtime. Removed; The "speed threshold" and "Tight" features were not copied over. This resembled too much to feature overkill. Needs re-evaluation. Also the "Deform" option was not added, I prefer to first check if the current particle system really works for the Modifier system. And: - Added integration for particle force fields in the dependency graph - Added TAB completion for vertexgroup names! - Made the 'wait cursor' only appear when particles take more than 0.5 sec - The particle jitter table order now is randomized too, giving much nicer emitting of particles in large faces. - Vortex field didn't correctly use speed/forces, so it didn't work for collisions. - Triangle distribution was wrong - Removed ancient bug that applied in a *very* weird way speed and forces. (location changes got the half force, speed the full...???) So much... might have forgotten some notes! :)
2005-11-10 16:01:56 +00:00
}
void BKE_effectors_apply(ListBase *effectors,
ListBase *colliders,
EffectorWeights *weights,
EffectedPoint *point,
float *force,
float *wind_force,
float *impulse)
{
/* WARNING(@ideasman42): historic comment?
* Many of these parameters don't exist!
*
2023-02-10 11:34:20 +11:00
* `scene` = scene where it runs in, for time and stuff.
* `lb` = listbase with objects that take part in effecting.
* `opco` = global coord, as input.
* `force` = accumulator for force.
* `wind_force` = accumulator for force only acting perpendicular to a surface.
* `speed` = actual current speed which can be altered.
* `cur_time` = "external" time in frames, is constant for static particles.
* `loc_time` = "local" time in frames, range <0-1> for the lifetime of particle.
* `par_layer` = layer the caller is in.
* `flags` = only used for soft-body wind now.
* `guide` = old speed of particle.
*/
2017-06-12 13:35:00 +10:00
/*
* Modifies the force on a particle according to its
* relation with the effector object
* Different kind of effectors include:
2023-02-10 11:34:20 +11:00
* - Force-fields: Gravity-like attractor
* (force power is related to the inverse of distance to the power of a falloff value)
* - Vortex fields: swirling effectors
* (particles rotate around Z-axis of the object. otherwise, same relation as)
* (Force-fields, but this is not done through a force/acceleration)
* - Guide: particles on a path
* (particles are guided along a curve bezier or old nurbs)
* (is independent of other effectors)
2017-06-12 13:35:00 +10:00
*/
EffectorData efd;
2018-09-25 11:41:29 +10:00
int p = 0, tot = 1, step = 1;
The long awaited Particle patch from Janne Karhu http://www.blender3d.org/cms/New_Particle_options_a.721.0.html There's no doubt this patch had a lot of good ideas for features, and I want to compliment Janne again for getting it all to work even! A more careful review of the features and code did show however quite some flaws and bugs... partially because the current particle code was very much polluted already, but also because of the implementation lacked quality. However, the patch was too good to reject, so I've fixed and recoded the parts that needed it most. :) Here's a list of of most evident changes in the patch; - Guides support recoded. It was implemented as a true 'force field', checking all Curve path points for each particle to find the closest. Was just far too slow, and didn't support looping or bends well. The new implementation is fast (real time) and treats the paths as actual trajectory for the particle. - Guides didn't integrate in the physics/speed system either, was added as exception. Now it's integrated and can be combined with other velocities or forces - Use of Fields was slow code in general, made it use a Cache instead. - The "even" distribution didn't work for Jittered sample patterns. - The "even" or "vertexgroup" code in the main loops were badly constructed, giving too much cpu for a simple task. Instead of going over all faces many times, it now only does it once. Same part of the code used a lot of temporal unneeded mallocs. - Use of DerivedMesh or Mesh was confused, didn't work for Subsurfs in all cases - Support for vertex groups was slow, evaluating vertexgroups too often - When a vertexgroup failed to read, it was wrongly handled (set to zero). VertexGroup support now is with a name. - Split up the too huge build_particle() call in some parts (moving new code) - The "texture re-timing" option failed for moving Objects. The old code used the convention that particles were added with increasing time steps. Solved by creating a object Matrix Cache. Also: the texture coordinates had to be corrected to become "OrCo". - The "Disp" option only was used to draw less particles. Changed it to actually calculate fewer particles for 3D viewing, but render all still. So now it can be used to keep editing realtime. Removed; The "speed threshold" and "Tight" features were not copied over. This resembled too much to feature overkill. Needs re-evaluation. Also the "Deform" option was not added, I prefer to first check if the current particle system really works for the Modifier system. And: - Added integration for particle force fields in the dependency graph - Added TAB completion for vertexgroup names! - Made the 'wait cursor' only appear when particles take more than 0.5 sec - The particle jitter table order now is randomized too, giving much nicer emitting of particles in large faces. - Vortex field didn't correctly use speed/forces, so it didn't work for collisions. - Triangle distribution was wrong - Removed ancient bug that applied in a *very* weird way speed and forces. (location changes got the half force, speed the full...???) So much... might have forgotten some notes! :)
2005-11-10 16:01:56 +00:00
/* Cycle through collected objects, get total of (1/(gravity_strength * dist^gravity_power)) */
/* Check for min distance here? (yes would be cool to add that, ton) */
2018-09-25 11:41:29 +10:00
if (effectors) {
LISTBASE_FOREACH (EffectorCache *, eff, effectors) {
2018-09-25 11:41:29 +10:00
/* object effectors were fully checked to be OK to evaluate! */
2018-09-25 11:41:29 +10:00
get_effector_tot(eff, &efd, point, &tot, &p, &step);
2018-09-25 11:41:29 +10:00
for (; p < tot; p += step) {
if (get_effector_data(eff, &efd, point, 0)) {
efd.falloff = effector_falloff(eff, &efd, point, weights);
2018-09-25 11:41:29 +10:00
if (efd.falloff > 0.0f) {
efd.falloff *= eff_calc_visibility(colliders, eff, &efd, point);
}
if (efd.falloff > 0.0f) {
float out_force[3] = {0, 0, 0};
if (eff->pd->forcefield == PFIELD_TEXTURE) {
do_texture_effector(eff, &efd, point, out_force);
}
else {
do_physical_effector(eff, &efd, point, out_force);
/* for softbody backward compatibility */
if (point->flag & PE_WIND_AS_SPEED && impulse) {
sub_v3_v3v3(impulse, impulse, out_force);
}
}
if (wind_force) {
madd_v3_v3fl(force, out_force, 1.0f - eff->pd->f_wind_factor);
madd_v3_v3fl(wind_force, out_force, eff->pd->f_wind_factor);
}
else {
add_v3_v3(force, out_force);
2018-09-25 11:41:29 +10:00
}
}
}
2018-09-25 11:41:29 +10:00
else if (eff->flag & PE_VELOCITY_TO_IMPULSE && impulse) {
/* special case for harmonic effector */
add_v3_v3v3(impulse, impulse, efd.vel);
}
}
}
}
}
/* ======== Simulation Debugging ======== */
SimDebugData *_sim_debug_data = nullptr;
2018-09-25 11:41:29 +10:00
uint BKE_sim_debug_data_hash(int i)
{
return BLI_ghashutil_uinthash(uint(i));
}
2018-09-25 11:41:29 +10:00
uint BKE_sim_debug_data_hash_combine(uint kx, uint ky)
{
2018-09-25 11:41:29 +10:00
#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
2018-09-25 11:41:29 +10:00
uint a, b, c;
a = b = c = 0xdeadbeef + (2 << 2) + 13;
a += kx;
b += ky;
2018-09-25 11:41:29 +10:00
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);
return c;
#undef rot
}
2018-09-25 11:41:29 +10:00
static uint debug_element_hash(const void *key)
{
const SimDebugElement *elem = static_cast<const SimDebugElement *>(key);
return elem->hash;
}
static bool debug_element_compare(const void *a, const void *b)
{
const SimDebugElement *elem1 = static_cast<const SimDebugElement *>(a);
const SimDebugElement *elem2 = static_cast<const SimDebugElement *>(b);
if (elem1->hash == elem2->hash) {
return false;
}
return true;
}
static void debug_element_free(void *val)
{
SimDebugElement *elem = static_cast<SimDebugElement *>(val);
MEM_freeN(elem);
}
void BKE_sim_debug_data_set_enabled(bool enable)
{
if (enable) {
if (!_sim_debug_data) {
_sim_debug_data = static_cast<SimDebugData *>(
MEM_callocN(sizeof(SimDebugData), "sim debug data"));
_sim_debug_data->gh = BLI_ghash_new(
debug_element_hash, debug_element_compare, "sim debug element hash");
}
}
else {
BKE_sim_debug_data_free();
}
}
bool BKE_sim_debug_data_get_enabled()
{
return _sim_debug_data != nullptr;
}
void BKE_sim_debug_data_free()
{
if (_sim_debug_data) {
2018-09-25 11:41:29 +10:00
if (_sim_debug_data->gh) {
BLI_ghash_free(_sim_debug_data->gh, nullptr, debug_element_free);
2018-09-25 11:41:29 +10:00
}
MEM_freeN(_sim_debug_data);
}
}
static void debug_data_insert(SimDebugData *debug_data, SimDebugElement *elem)
{
SimDebugElement *old_elem = static_cast<SimDebugElement *>(
BLI_ghash_lookup(debug_data->gh, elem));
if (old_elem) {
*old_elem = *elem;
MEM_freeN(elem);
}
2018-09-25 11:41:29 +10:00
else {
BLI_ghash_insert(debug_data->gh, elem, elem);
2018-09-25 11:41:29 +10:00
}
}
2018-09-25 11:41:29 +10:00
void BKE_sim_debug_data_add_element(int type,
const float v1[3],
const float v2[3],
const char *str,
float r,
float g,
float b,
const char *category,
uint hash)
{
2018-09-25 11:41:29 +10:00
uint category_hash = BLI_ghashutil_strhash_p(category);
SimDebugElement *elem;
if (!_sim_debug_data) {
2018-09-25 11:41:29 +10:00
if (G.debug & G_DEBUG_SIMDATA) {
BKE_sim_debug_data_set_enabled(true);
2018-09-25 11:41:29 +10:00
}
else {
return;
2018-09-25 11:41:29 +10:00
}
}
elem = static_cast<SimDebugElement *>(
MEM_callocN(sizeof(SimDebugElement), "sim debug data element"));
elem->type = type;
elem->category_hash = category_hash;
elem->hash = hash;
elem->color[0] = r;
elem->color[1] = g;
elem->color[2] = b;
2018-09-25 11:41:29 +10:00
if (v1) {
copy_v3_v3(elem->v1, v1);
2018-09-25 11:41:29 +10:00
}
else {
zero_v3(elem->v1);
2018-09-25 11:41:29 +10:00
}
if (v2) {
copy_v3_v3(elem->v2, v2);
2018-09-25 11:41:29 +10:00
}
else {
zero_v3(elem->v2);
2018-09-25 11:41:29 +10:00
}
if (str) {
2023-05-09 12:50:37 +10:00
STRNCPY(elem->str, str);
2018-09-25 11:41:29 +10:00
}
else {
elem->str[0] = '\0';
2018-09-25 11:41:29 +10:00
}
debug_data_insert(_sim_debug_data, elem);
}
2018-09-25 11:41:29 +10:00
void BKE_sim_debug_data_remove_element(uint hash)
{
SimDebugElement dummy;
2018-09-25 11:41:29 +10:00
if (!_sim_debug_data) {
return;
2018-09-25 11:41:29 +10:00
}
dummy.hash = hash;
BLI_ghash_remove(_sim_debug_data->gh, &dummy, nullptr, debug_element_free);
}
void BKE_sim_debug_data_clear()
{
2018-09-25 11:41:29 +10:00
if (!_sim_debug_data) {
return;
2018-09-25 11:41:29 +10:00
}
if (_sim_debug_data->gh) {
BLI_ghash_clear(_sim_debug_data->gh, nullptr, debug_element_free);
2018-09-25 11:41:29 +10:00
}
}
void BKE_sim_debug_data_clear_category(const char *category)
{
int category_hash = int(BLI_ghashutil_strhash_p(category));
2018-09-25 11:41:29 +10:00
if (!_sim_debug_data) {
return;
2018-09-25 11:41:29 +10:00
}
if (_sim_debug_data->gh) {
GHashIterator iter;
BLI_ghashIterator_init(&iter, _sim_debug_data->gh);
2015-01-24 01:59:09 +11:00
while (!BLI_ghashIterator_done(&iter)) {
const SimDebugElement *elem = static_cast<const SimDebugElement *>(
BLI_ghashIterator_getValue(&iter));
/* Removing invalidates the current iterator, so step before removing. */
BLI_ghashIterator_step(&iter);
2018-09-25 11:41:29 +10:00
if (elem->category_hash == category_hash) {
BLI_ghash_remove(_sim_debug_data->gh, elem, nullptr, debug_element_free);
2018-09-25 11:41:29 +10:00
}
}
}
}