利用者:Aligorith/Effectors Integration
目次
Disclaimer
This page has been written by a coder more focused on animation-aspects of 3D Graphics and computer software in general, rather than a physicist or specialised physics-coder (or an architect of the system described here). For that reason, please excuse any non "physically-correct" statements, as physics is really not a strongpoint of the author. --Aligorith 06:15, 8 August 2010 (UTC)
What are they?
Effectors (also known as Force Fields) are a way to impose some constraints/effects on physics simulations. An example of effectors that are commonly used for practical situations are Wind and Vortex.
The basic idea is that each field exerts some force upon each 'particle' that is within reach of it (think magnetic fields a metal filings aligning themselves with the field lines).
Introduction to the Code
Most of the code you'll need for dealing with them is in two files (not the exact paths, but just the module/filename pairs to help you find them):
makesdna/DNA_object_force.h - definitions blenkernel/effect.c - code to make it all work
These two files together form the basis for the "unified API" for working with Effectors. Most of the time, you can just treat all the code there as blackboxes that you just need to feed your specific simulation state into and get out some useful information that you can then use in your physics simulator.
Using Effectors
For the top-level container...
Here we're talking about the simulation environment: a particle-system base or Rigid Body simulation world, which defines all of the elements in a simulation that a simulator has to care about and which will need to interact with the effectors.
Adding:
There's one thing that we need to do here, which is to store an
EffectorWeights
pointer here when this container is created. Use the following code snippet to do this:
simBase->effector_weights = BKE_add_effector_weights(group);
From what I understand, this data-structure keeps track of the influence of each effector in a simulation (though that capacity doesn't actually seem to be used yet anywhere?). More importantly (IMO) is the
Group *group
instance it keeps (i.e. the "group" arg in the code above), defining the group where participants in the simulation (i.e. elements to be affected by the effectors and the effectors too) come from.
Mem-Management: Just use the standard GuardedAlloc calls (MEM_*) to copy and free this data.
Per Element involved in the Simulation
Within your simulation step, but before letting the physics simulator perform its magic, you need to determine the effects of the force fields on that element so that the physics simulator can take them into account.
Here is the code that you'll need to run (it can be broken up a bit to fit in with your code):
EffectorWeights *effector_weights = simBase->effector_weights;
EffectedPoint epoint;
ListBase *effectors;
/* get effectors present in the group specified by effector_weights */
effectors = pdInitEffectors(scene, ob, NULL, effector_weights);
if (effectors) {
float force[3] = {0.0f, 0.0f, 0.0f};
float loc[3], vel[3];
/* create dummy 'point' which represents last known position of element as result of sim */
//loc = mySim_get_location(simBase, element)
//vel = mySim_get_velocity(simBase, element)
pd_point_from_loc(scene, loc, vel, 0, &epoint); // the exact version depends on the physics simulator. Check out the functions like this from effects.c
/* calculate net force of effectors, and apply to sim object */
pdDoEffectors(effectors, NULL, effector_weights, &epoint, force, NULL);
//mySim_apply_force(simBase, element)
}
/* cleanup */
pdEndEffectors(&effectors);
So really, it's a 4 step process:
- 1) Get effectors affecting the simulation
- 2) Wrap up evaluation element as a 'EffectedPoint'
- 3) Determine the 'net' force of the effectors on that point
- 4) Tell simulator about this force acting on the element
Consider this process using the following analogy: imagine grabbing a bunch of arrows pointing in different directions, "mushing" them together inside a bag (or some dark void you cannot see inside/know anything about), and getting a single "big" arrow pointing in the direction that the combination of arrows were pointing before.
Each of those original little arrows was a vector describing the force being applied to the element by one of the force fields (thinking of the magnetic fields helps here). The "big arrow" (it might be small, but more likely it will be bigger than many of the original arrows) is the net force, or the single force that once applied would be equivalent to applying each of the individual forces in sequence. So, the "mushing" step is really just what we do to combine these individual forces to get the single force (usually that's probably just the sum of all the vectors).
Things to Be Wary About
Checking for Effectors
Effectors are just objects, objects with ob->pd storing effector settings to be precise.
Now, there's a bit of a gotcha here: before adding any effectors (or collision settings),
ob->pd == NULL
However, once an effector exists in the scene,
ob->pd != NULL
for ALL OBJECTS regardless of whether they're effectors or not.
So really, you need to check for two things:
- (ob->pd != NULL), AND
- (ob->pd->forcefield != PFIELD_NULL)
in order to determine if an object is an effector. PFIELD_NULL means object isn't an effector.
Objects affected by effectors
If you simulator needs to affect objects (i.e. as the Rigid Body engine does), then you'll need to consider one other problem.
That is, you MUST check that you're not trying to calculate the net force applied by all effectors on an effector itself. So, the checks in the previous section become:
- (ob->pd == NULL), OR
- (ob->pd->forcefield == PFIELD_NULL)
where PFIELD_NULL means object isn't an effector.