openframeworks freakday s03e02 diederick huijbers - c++/physics/cloth animation/templates
DESCRIPTION
Presentation given at the monthly "freakDays" meetings in Amsterdam on Creative Coding.TRANSCRIPT
This presentation is part of the openFrameworks freakDays meetings which are given by a group of
Creative Coders and artists in Amsterdam.
During these monthly meetings we give presentation on innovative techniques and show
projects we’re involved in.
For more information checkout www.roxlu.com or contact us at [email protected]
c++ templates Physics
Cloth
Basic C++structsclassespointers
templates<>
struct Particle { float x; float y; float mass;}
Particle
xy
mass
... use the keyword “struct”
.. green means “members are accessible”..
class Particle { float x; float y; float mass;}
Particle
xy
mass
... use the keyword “class”
.. red means “members are NOT accessible”..
Differences:Struct members are
public by default those of a class not.
class Particle { float x; float y; float mass;}
Particle
xy
mass
Particle
xy
mass
Particle
xy
mass
A struct doesn’t need thispublic keyword. Their members are public by default! That’s nice!
class Particle {public: float x; float y; float mass;}
struct Particle { float x; float y; float mass;}
Check how the keyword public makes the members green ;) and so accessible!
When to use struct <-> class?It doesn’t really matter; it’s a personal thing....
...though, typically structsare used for simple datacontainers and classes
for more advanced things.
class Particle {public: Particle(); void setPosition(float x, float y); void update(); void draw(); void applyRepulsiveForce(); void addForce(float x, float y);
private: float x; float y; float mass;}
Classes for more advanced stuff
struct User { string name; string password; string homepage; int age; float weight;};
struct Tweet { uint16 userid; string homepage; string avatar_url; int timestamp; bool has_gps;};
Structs for simple data containers
Pointers !!!
Pointers are not that hard!Instead of pointing to a
value hold a a memory address!
Pointers are not that hardValues Address in memory
f #1
r #2
e #3
a #4
k #5
d #6
a #7
y #8
Values Address in memory
f #1
r #2
e #3
a #4
k #5
d #6
a #7
y #8
\0 #9
? #10
? #11
char* name = “freakday”
name + 0
name + 1
name + 2
name + 3
name + 4
name + 5
name + 6
name + 7
name + 8
char *Check the char* the star (*) tells the compiler we want a pointer a char. A normal char is just one character. The \0 is automatically added and tells the compiler it’s the end of the “string”
A pointer points hold an memory address. We can step through the memory addresses using this type of variable.
Values
f #1
r #2
e #3
a #4
k #5
d #6
a #7
y #8
\0 #9
? #10
? #11
name + 9
name + 10
Do not go into unauthorized memory ....or else.....
“EXC_BAD_ACCESS” or“UNDEFINED” behavior
...which is ....
Check XCode project “freakday_S03E02_pointers”
Memory Alignment + packing
class Particle { bool enabled; // 8 bits float x; // 32 bits float y; // 32 bits bool flying; // 8 bits}
enabled
xy
flying
= memory needed
= memory actually used
}32 bit wide
WRONG!You should align your bytes nicely
When the CPU reads from memory it uses a natural alignment which must be respected to permit the CPU to read and write memory effectively. A compiler will leave holes in memory when members/objects aren’t aligned properly.
}
Memory Alignment + packing
class Particle { float x; // 32 bits float y; // 32 bits bool flying; // 8 bits bool enabled; // 8 bits}
xy
f
= memory needed
= memory actually used
32 bit wide
CORRECT!The members are aligned nicely
e
Memory Alignment + packing
Check XCode project “freakday_S03E02_packing”
[TYPE_ADDRESS]: some value[ADDRESS_ENTRY]: some value
[TYPE_PHONE]: some value
Templates
Office address: some valueBilling address: some valueMobile phone: some valueWork phone: some value
Templates
Templates are a way to write more generic code: write one special thing (algorithm) which you can use for many kind of types.
Create one template for a particle for both 2D and 3D. Particle<2D> and Particle<3D>
Templates
class Particle2D { ofVec2f position; ofVec2f velocity; ofVec2f forces; void draw();}
class 2DParticlesGroup { vector<Particle2D*> particles; void addForce(ofVec2f f) { for(int i = 0; i < particles.size(); ++i) { particles.at(i)->addForce(f); } }}
2D particles....
Particle-Group
Particle
class Particle3D { ofVec3f position; ofVec3f velocity; ofVec3f forces; void draw();}
class 3DParticlesGroup { vector<Particle3D*> particles; void addForce(ofVec3f f) { for(int i = 0; i < particles.size(); ++i) { particles.at(i)->addForce(f); } }}
3D particles....
Particle-Group
Particle
class Particle4D { ofVec4f position; ofVec4f velocity; ofVec4f forces; void draw();}
class 4DParticlesGroup { vector<Particle4D*> particles; void addForce(ofVec4f f) { for(int i = 0; i < particles.size(); ++i) { particles.at(i)->addForce(f); } }}
4D particles....
Particle-Group
Particle
5D, 6D, 7D ... or templateAdd this before your template class: “template<typename T>”.
The “T” is the type parameter: Particle2D, Particle3D, etc..The name “T” can be anything you like, but T is convention.
Also correct:template<typename SomeType>template<class SomeType>template<class T>
“Typename” and “class” can be used both, “typename”is preferred.
template<typename T>class Particle {public: Particle(T oPosition, float nMass); void addForce(T oForce); void update(); void draw();
private: T position; T forces; T velocity; float mass;};
Templated Particle
template<typename P, typename V>class ParticleGroup {public: ParticleGroup(); void addParticle(P oParticle); void addForce(V oForce); void update(); void draw();
private: vector<P> particles};
Templated Particle-Group
template<typename P, typename V>class ParticleGroup {public: ParticleGroup(); void addParticle(P oParticle); void addForce(V oForce); void update(); void draw();
private: vector<P> particles};
Example of templated particles
Check XCode project “freakday_S03E02_templates”
Keyword TypenameConsider the following code:
template<typename T>class SomeClass {public: typename T::SubType* ptr;};
Makes sure that subtype is seen as a type, not a static member.
template<typename T>class SomeClass {public: typename T::MyType* ptr;};
template<typename T>class SomeClass {public:
T::MyType* ptr;};
WRONG: Here T::MyType * ptr would mean a multiplication
class WithStatic {public: static int MyType;}
Here T::MyType * ptr would refer to the nested type in the WithType class.
class WithType {public: class MyType { }}
-- pseudo code --template<typename T>class MyContainer { vector<T> items; void draw() { typename vector<T>::iterator it = items.begin(); while(it != items.end()) { (*it)->draw(); ++it; } }};
-- add some particles to containerMyContainer<Particle2D*> particles;particles.items.push_back(new Particle2D()); particles.items.push_back(new Particle2D());particles.draw();
When to use the keyword typename
Here we make sure that iterator is a type, not a static member! Usually you use the keyword typename with STL iterators
Physics
An object continues with constant velocity unless a
force acts upon it [1]
Newtons first law
Newtons first law
1 2 3 4 5 6 7time and position
Velocity vector(s):ofxVec2f, ofxVec3f
Note that the red arrow stays the same size. The red arrow represents the velocity vector and showing the first law
Check XCode project “freakday_S03E02_5_simple_motion”
1 2 3 4 5 6 7time and position
When creating particle systems I often simulate drag by degreasing the velocity by a small percentage.
Note how the velocity vector below get’s smaller.
Check XCode project “freakday_S03E02_6_simple_motion_with_drag”
// example faking dragvoid Particle::update() { velocity *= 0.98;}
The amount of drag, the 0.98 in this example, totally depends on what you want. It’s a case of tweaking to get the right behavior.
A force acting on a object produces acceleration that
is proportional to the object’s mass. [1]
Newtons second law
Newtons second law
this arrow represents the force acting on the object
this is the resulting forcewhen mass is taken intoaccount
160-200 KG (?)
Newtons second law
this arrow represents the force acting on the object
this is the resulting forcewhen mass is taken intoaccount
75-80 KG
Newtons second law
force = mass * acceleration
The math of how force, acceleration and mass is related....
...to get the acceleration we do:
“The law” ( F = ma )
this is what I use in particle systems
acceleration = 1/mass * force
Newtons second law
acceleration = 1/mass * force
This one is important! The bigger the mass, the less the
acceleration
This is what we call inverse mass. We do not need to recalculate this for each update! We store this in a member of the Particle class and can be used to represent “infinite” mass when set to zero:
0 * force = 0
class Particle { ofxVec2f position; ofxVec2f velocity; ofxVec2f forces; float inverse_mass; Particle(float fMass) { if(mass <= 0) { inverse_mass = 0; } else { inverse_mass = 1/mass; } }
void addForce(ofxVec2f oForce) { forces += oForce; } void update() { forces *= inverse_mass; velocity += forces; velocity *= 0.99; position += velocity; forces.set(0,0); }};
How does this look like in code?
Check XCode project “freakday_S03E02_7_simple_motion_inverse_mass”
D’Alembert’s Principle (simplified):We can accumulate all forces acting on an object.
“Springs are structural elements that, when
connected between two objects, apply equal and opposite forces to each
object.”
Springs
Springs
Object 2Object 1
The red arrows represent force vectors in opposite directions: so the two objects are pulled towards each other
Springs
-k = spring strength; in code just a “float strength” which often gets a value like 0.1, 0.001
The rule related to springsforces is called “Hooks” law!
f = -k∆L
∆L = difference between springs “compressed/rest length” and current length.
∆L = (r - d)difference between springs
“compressed/rest length” and current length.
Two springs not stretched/compressed and showing their rest length. }
r = rest length
∆L = (r - d)
(r) rest length
Two particles connected by a spring
(d) distance
Spring force vector Spring force vector
(d) distance
Spring force vector Spring force vector
template<typename P, typename V>class Spring {public:! Spring(P pParticleA, P pParticleB, float nStrength = 0.01) ! :a(pParticleA)! ,b(pParticleB)! ,k(nStrength)! {! ! rest_length = (b->position - a->position).length();! }
! void update() {! ! V dir = b->position - a->position;! ! float dist = dir.length();! ! if(dist == 0.0) {! ! ! dist = 0.0001; // division by zero! ! } ! !! ! float f = (rest_length - dist) * k; ! ! dir.normalize();! ! a->addForce(dir * -f);! ! b->addForce(dir * f);! }!! P a,b;
Spring template 2d/3d/..
Rest length
Rest length: distance between particles when
creating the spring
Current distance
The force spring
Force spring multiplied by normalized direction vector and in opposite directions
Springs
Check XCode project “freakday_S03E02_8_spring_forces”
Check XCode project “freakday_S03E02_9_spring_forces_with_gui”
Example: click mouse to add particle + spring...
Example: right click mouse to add particle + spring and use sliders to see the result of
different “k” and “drag” values.
Cloth Physics
Cloth PhysicsSimple cloth physics used multiple springs connected
to particles in a grid.
Cloth Physics
Particles are positioned on a grid and then connected by 3 kind of springs:
- structural springs- shear springs- bending springs
Cloth PhysicsStructural springs
Cloth PhysicsShear springs
Cloth Physics
Bending springs
Errors
are
beauti
ful :)
Check XC
ode project “freakday_S03E02_10_cloth”
// lets create the grid.for(int i = 0; i < nCols; ++i) {! for(int j = 0; j < nRows; ++j) {! ! ofxVec3f position(i * nSize, j * nSize);! ! Particle3D* particle = new Particle3D(position, 1.1);! ! particles[j * cols + i] = particle;! ! if(j == 0) {! ! ! particle->inverse_mass = 0;! ! }! }}
Creating the particle grid
Calculating the index in the vector. We position the particle just like normal image pixels are stored, by column and row. This is handy when we need to lookup (see getAt) a particle based on a column
and row.
// create springs.Particle3D* a;Particle3D* b;for(int i = 0; i < nCols; ++i) {! for(int j = 0; j < nRows; ++j) {! !! ! // structural spring - right.! ! if(i < nCols-1) {! ! ! a = getAt(i,j);!! ! ! b = getAt(i+1, j);! ! ! springs.createSpring(a,b);! ! }! !! ! // structural spring - down! ! if(j < nRows-1) {! ! ! a = getAt(i,j);! ! ! b = getAt(i, j+1);! ! ! springs.createSpring(a,b);! ! }! }}
For more info on how to create the other springs see the source; it’s quite similar.
Creating the structural springs
Check XCode project “freakday_S03E02_11_with_gui”
Next time C++/...:
Initializer listsVirtual functionsInheritance More templates.....Debugging linker errors (file, nm)Operator overloading (=,[],*,etc.)Const, static
Integrators (euler, verlet, runge kutta)
Fast particle systems (buckets, sorting)
BillboardingMatrices / 3DShaders
Next time particles/3d
....
Other suggestions...
References1. Ian Millington, Game Physics Engine Development, 2007