mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-15 00:54:38 +00:00
New filters parameters added; Fill filter improved
This commit is contained in:
parent
ffb4a528ad
commit
8cd228d5c4
@ -2,17 +2,18 @@
|
||||
|
||||
#include <vcg/complex/trimesh/append.h>
|
||||
|
||||
DynamicMeshSubFilter::DynamicMeshSubFilter() : m_fps(-1), m_iterations(-1), m_contacts(-1), m_steps(-1), m_seconds(-1), m_bounciness(-1) {
|
||||
DynamicMeshSubFilter::DynamicMeshSubFilter() : m_fps(-1), m_iterations(-1), m_contacts(-1), m_steps(-1), m_seconds(-1), m_bounciness(-1), m_gravity(-1) {
|
||||
}
|
||||
|
||||
void DynamicMeshSubFilter::initParameterSet(QAction* action,MeshDocument& md, RichParameterSet & par){
|
||||
MeshSubFilter::initParameterSet(action, md, par);
|
||||
par.addParam(new RichFloat("gravity", -1.f, "Gravity", "Gravity force value"));
|
||||
par.addParam(new RichInt("seconds", 10, "Simulation interval (sec)", "Physics simulation interval in seconds"));
|
||||
par.addParam(new RichDynamicFloat("timeline", 0, 0, 100, "Timeline %", "Controls the point in timeline of the simulation"));
|
||||
}
|
||||
|
||||
bool DynamicMeshSubFilter::applyFilter(QAction* filter, MeshDocument &md, RichParameterSet& par, vcg::CallBackPos* cb){
|
||||
if(par.getInt("seconds") < 0 || par.getInt("fps") <= 0 || par.getInt("iterations") <= 0 || par.getInt("contacts") <= 0 || par.getFloat("bounciness") < 0 || par.getFloat("bounciness") > 1)
|
||||
if(parametersAreNotCorrect(md, par))
|
||||
return false;
|
||||
|
||||
if(configurationHasChanged(md, par))
|
||||
@ -21,29 +22,18 @@ bool DynamicMeshSubFilter::applyFilter(QAction* filter, MeshDocument &md, RichPa
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DynamicMeshSubFilter::parametersAreNotCorrect(MeshDocument& md, RichParameterSet& par){
|
||||
return par.getInt("seconds") < 0 || par.getInt("fps") <= 0 || par.getInt("iterations") <= 0 || par.getInt("contacts") <= 0 || par.getFloat("bounciness") < 0 || par.getFloat("bounciness") > 1;
|
||||
}
|
||||
|
||||
bool DynamicMeshSubFilter::configurationHasChanged(MeshDocument& md, RichParameterSet& par){
|
||||
bool changed = m_seconds != par.getInt("seconds");
|
||||
changed |= m_fps != par.getInt("fps");
|
||||
changed |= m_iterations != par.getInt("iterations");
|
||||
changed |= m_contacts != par.getInt("contacts");
|
||||
changed |= m_bounciness != par.getFloat("bounciness");
|
||||
|
||||
// Does not work because meshlab fails at restoring the original translation matrix in the preview checkbox logic
|
||||
/* Dim: the transformation matrices should not change
|
||||
for(int i = 0; i < md.size(); i++){
|
||||
for(int j = 0; j < 16; j++) std::cout << md.getMesh(i)->cm.Tr[j/4][j%4] <<" ";
|
||||
std::cout<<std::endl;
|
||||
}
|
||||
*/
|
||||
|
||||
/*if(md.size() == m_state.size()){
|
||||
for(int i = 0; i < m_state.size() && !changed; i++){
|
||||
changed |= !compareMesh(md.getMesh(i), m_state[i]);
|
||||
}
|
||||
}else
|
||||
changed = true;
|
||||
|
||||
saveMeshState(md);*/
|
||||
changed |= m_gravity != par.getFloat("gravity");
|
||||
changed |= m_friction != par.getFloat("friction");
|
||||
|
||||
if(md.size() == m_files.size())
|
||||
for(int i = 0; i < m_files.size(); i++)
|
||||
@ -60,24 +50,12 @@ bool DynamicMeshSubFilter::configurationHasChanged(MeshDocument& md, RichParamet
|
||||
m_iterations = par.getInt("iterations");
|
||||
m_contacts = par.getInt("contacts");
|
||||
m_bounciness = par.getFloat("bounciness");
|
||||
m_gravity = par.getFloat("gravity");
|
||||
m_friction = par.getFloat("friction");
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool DynamicMeshSubFilter::compareMesh(MeshModel* m1, MeshModel* m2){
|
||||
return m1->fileName == m2->fileName && m1->cm.Tr == m2->cm.Tr;
|
||||
}
|
||||
|
||||
void DynamicMeshSubFilter::saveMeshState(MeshDocument& md){
|
||||
m_state.clear();
|
||||
for(int i = 0; i < md.size(); i++){
|
||||
MeshModel* meshCopy = new MeshModel();
|
||||
vcg::tri::Append<CMeshO,CMeshO>::Mesh(meshCopy->cm, md.getMesh(i)->cm, false, true);
|
||||
meshCopy->fileName = md.getMesh(i)->fileName;
|
||||
meshCopy->cm.Tr = md.getMesh(i)->cm.Tr;
|
||||
m_state.push_back(meshCopy);
|
||||
}
|
||||
}
|
||||
|
||||
void DynamicMeshSubFilter::initialize(MeshDocument&, RichParameterSet&, vcg::CallBackPos* cb){
|
||||
void DynamicMeshSubFilter::initialize(MeshDocument& md, RichParameterSet& par, vcg::CallBackPos* cb){
|
||||
MeshSubFilter::initialize(md, par, cb);
|
||||
m_steps = m_seconds * m_fps;
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ public:
|
||||
DynamicMeshSubFilter();
|
||||
virtual void initParameterSet(QAction* action,MeshDocument& md, RichParameterSet & par);
|
||||
virtual bool applyFilter(QAction* filter, MeshDocument &md, RichParameterSet& par, vcg::CallBackPos* cb);
|
||||
virtual bool parametersAreNotCorrect(MeshDocument& md, RichParameterSet& par);
|
||||
|
||||
protected:
|
||||
typedef std::vector<vcg::Matrix44f> LayerTransformations;
|
||||
@ -20,7 +21,6 @@ protected:
|
||||
|
||||
virtual void initialize(MeshDocument&, RichParameterSet&, vcg::CallBackPos* cb);
|
||||
virtual bool configurationHasChanged(MeshDocument& md, RichParameterSet& par);
|
||||
void saveMeshState(MeshDocument& md);
|
||||
|
||||
int m_fps;
|
||||
int m_iterations;
|
||||
@ -28,13 +28,12 @@ protected:
|
||||
int m_steps;
|
||||
int m_seconds;
|
||||
float m_bounciness;
|
||||
float m_gravity;
|
||||
float m_friction;
|
||||
|
||||
LayersTransformations m_layersTrans;
|
||||
std::vector<std::string> m_files;
|
||||
std::vector<MeshModel*> m_state;
|
||||
|
||||
private:
|
||||
bool compareMesh(MeshModel* m1, MeshModel* m2);
|
||||
};
|
||||
|
||||
#endif // DYNAMICMESHSUBFILTER_H
|
||||
|
||||
@ -13,9 +13,6 @@ void GravitySubFilter::initParameterSet(QAction* action,MeshDocument& md, RichPa
|
||||
}
|
||||
|
||||
bool GravitySubFilter::applyFilter(QAction* filter, MeshDocument &md, RichParameterSet& par, vcg::CallBackPos* cb){
|
||||
if(md.size() < 2 || par.getMesh("scenery") == 0)
|
||||
return false;
|
||||
|
||||
if(!DynamicMeshSubFilter::applyFilter(filter, md, par, cb))
|
||||
return false;
|
||||
|
||||
@ -27,6 +24,10 @@ bool GravitySubFilter::applyFilter(QAction* filter, MeshDocument &md, RichParame
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GravitySubFilter::parametersAreNotCorrect(MeshDocument& md, RichParameterSet& par){
|
||||
return DynamicMeshSubFilter::parametersAreNotCorrect(md, par) || md.size() < 2 || par.getMesh("scenery") == 0;
|
||||
}
|
||||
|
||||
bool GravitySubFilter::configurationHasChanged(MeshDocument& md, RichParameterSet& par){
|
||||
bool changed = DynamicMeshSubFilter::configurationHasChanged(md, par) || m_scenery != par.getMesh("scenery") || m_currentFilterType != m_filterType;
|
||||
m_scenery = par.getMesh("scenery");
|
||||
@ -39,12 +40,13 @@ void GravitySubFilter::initialize(MeshDocument& md, RichParameterSet& par, vcg::
|
||||
|
||||
if(cb != 0) (*cb)(0, "Physics pre-renderization of the scene started...");
|
||||
|
||||
static float gravity[3] = {0.0f, -9.8f, 0.0f};
|
||||
float gravity[3] = {0.0f, m_gravity, 0.0f};
|
||||
m_engine.clear(md);
|
||||
m_engine.setGlobalForce(gravity);
|
||||
m_engine.setIterations(m_iterations);
|
||||
m_engine.setMaxContacts(m_contacts);
|
||||
m_engine.setBounciness(m_bounciness);
|
||||
m_engine.setFriction(m_friction);
|
||||
|
||||
for(int i = 0; i < md.size(); i++)
|
||||
m_engine.registerTriMesh(*md.getMesh(i), m_scenery == md.getMesh(i) ? true : false);
|
||||
@ -62,6 +64,7 @@ void GravitySubFilter::initialize(MeshDocument& md, RichParameterSet& par, vcg::
|
||||
for(int j = 0; j < md.size(); j++){
|
||||
m_layersTrans[j].push_back(m_engine.getTransformationMatrix(*md.getMesh(j)));
|
||||
}
|
||||
|
||||
m_engine.integrate(1.0f / m_fps);
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,7 @@ public:
|
||||
|
||||
virtual void initParameterSet(QAction* action,MeshDocument& md, RichParameterSet & par);
|
||||
virtual bool applyFilter(QAction* filter, MeshDocument &md, RichParameterSet& par, vcg::CallBackPos* cb);
|
||||
virtual bool parametersAreNotCorrect(MeshDocument& md, RichParameterSet& par);
|
||||
|
||||
protected:
|
||||
virtual void initialize(MeshDocument&, RichParameterSet&, vcg::CallBackPos* cb);
|
||||
|
||||
@ -10,4 +10,14 @@ void MeshSubFilter::initParameterSet(QAction* action,MeshDocument& md, RichParam
|
||||
par.addParam(new RichInt("iterations", 20, "Physics method iterations", "Number of iterations of the physics iterative method for equation solving"));
|
||||
par.addParam(new RichInt("contacts", 20, "Max contacts", "Maximum number of contact points to generate per object pair"));
|
||||
par.addParam(new RichFloat("bounciness", 0.1f, "Bounciness", "The amount of bounciness of a collision: 0 means the surfaces are not bouncy at all, 1 is the maximum bounciness"));
|
||||
par.addParam(new RichFloat("friction", 10, "Friction", "The coulomb friction coefficient of a collision"));
|
||||
}
|
||||
|
||||
void MeshSubFilter::initialize(MeshDocument& md, RichParameterSet&, vcg::CallBackPos* cb){
|
||||
/*if(md.mm()->cm.Tr != vcg::Matrix44f::Identity())
|
||||
throw MatrixNotFreezedException();*/
|
||||
}
|
||||
|
||||
void MeshSubFilter::clearLastAppliedFilter(){
|
||||
m_currentFilterType = 0;
|
||||
}
|
||||
|
||||
@ -8,12 +8,24 @@
|
||||
#include <common/meshmodel.h>
|
||||
#include <common/interfaces.h>
|
||||
|
||||
#include <exception>
|
||||
|
||||
class MatrixNotFreezedException : public std::exception{
|
||||
public:
|
||||
const char* what() const throw(){
|
||||
return "The matrix of the current selected mesh has to be frozen";
|
||||
}
|
||||
};
|
||||
|
||||
class MeshSubFilter{
|
||||
public:
|
||||
MeshSubFilter();
|
||||
|
||||
virtual void initParameterSet(QAction* action,MeshDocument& md, RichParameterSet & par);
|
||||
virtual bool applyFilter(QAction* filter, MeshDocument &md, RichParameterSet& par, vcg::CallBackPos* cb) = 0;
|
||||
virtual void initialize(MeshDocument&, RichParameterSet&, vcg::CallBackPos* cb);
|
||||
|
||||
static void clearLastAppliedFilter();
|
||||
|
||||
protected:
|
||||
static int m_currentFilterType;
|
||||
|
||||
@ -10,6 +10,7 @@ using namespace vcg;
|
||||
|
||||
bool ODEFacade::m_initialized;
|
||||
float ODEFacade::m_bounciness = 0.1f;
|
||||
float ODEFacade::m_friction = 10.f;
|
||||
|
||||
dSpaceID ODEFacade::m_space;
|
||||
std::vector<dContact> ODEFacade::m_contacts(20);
|
||||
@ -31,14 +32,9 @@ void ODEFacade::initialize(){
|
||||
}
|
||||
|
||||
void ODEFacade::clear(MeshDocument& md){
|
||||
for(MeshContainer::iterator i = m_registeredMeshes.begin(); i != m_registeredMeshes.end(); i++){
|
||||
/*if(tri::HasPerMeshAttribute(i->first->cm, "physicsID"))
|
||||
tri::Allocator<CMeshO>::DeletePerMeshAttribute(i->first->cm, "physicsID");*/
|
||||
|
||||
for(MeshIterator i = m_registeredMeshes.begin(); i != m_registeredMeshes.end(); i++){
|
||||
dGeomDestroy(i->second->geom);
|
||||
if(i->second->body)
|
||||
dBodyDestroy(i->second->body);
|
||||
|
||||
if(i->second->body) dBodyDestroy(i->second->body);
|
||||
delete i->second;
|
||||
}
|
||||
m_registeredMeshes.clear();
|
||||
@ -49,8 +45,12 @@ void ODEFacade::setGlobalForce(float force[3]){
|
||||
}
|
||||
|
||||
void ODEFacade::registerTriMesh(MeshModel& mesh, bool scenery){
|
||||
if(tri::HasPerMeshAttribute(mesh.cm, "physicsID"))
|
||||
tri::Allocator<CMeshO>::DeletePerMeshAttribute(mesh.cm, "physicsID");
|
||||
MeshIterator entry = m_registeredMeshes.find(&mesh);
|
||||
if(entry != m_registeredMeshes.end())
|
||||
return;
|
||||
|
||||
if(!scenery && hasBorders(mesh))
|
||||
throw ODEInvalidMeshException();
|
||||
|
||||
if(mesh.cm.Tr != vcg::Matrix44f::Identity()){
|
||||
vcg::tri::UpdatePosition<CMeshO>::Matrix(mesh.cm, mesh.cm.Tr);
|
||||
@ -86,52 +86,51 @@ void ODEFacade::registerTriMesh(MeshModel& mesh, bool scenery){
|
||||
|
||||
odeMesh->data = dGeomTriMeshDataCreate();
|
||||
dGeomTriMeshDataBuildSingle1(odeMesh->data, odeMesh->vertices, 3*sizeof(dReal), mesh.cm.vert.size(), odeMesh->indices, 3*mesh.cm.face.size(), 3*sizeof(dTriIndex), odeMesh->normals);
|
||||
|
||||
odeMesh->geom = dCreateTriMesh(m_space, odeMesh->data, 0, 0, 0);
|
||||
|
||||
MeshIndex index = tri::Allocator<CMeshO>::AddPerMeshAttribute<unsigned int>(mesh.cm, "physicsID");
|
||||
index() = m_registeredMeshes.size();
|
||||
m_registeredMeshes.push_back(make_pair(&mesh, odeMesh));
|
||||
|
||||
m_registeredMeshes.insert(make_pair(&mesh, odeMesh));
|
||||
setAsRigidBody(mesh, !scenery);
|
||||
}
|
||||
|
||||
bool ODEFacade::hasBorders(MeshModel& mesh){
|
||||
for(CMeshO::FaceIterator i = mesh.cm.face.begin(); i != mesh.cm.face.end(); i++)
|
||||
for(int j = 0; j < 3; j++)
|
||||
if(vcg::face::IsBorder(*i, j)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void ODEFacade::setAsRigidBody(MeshModel& mesh, bool isRigidBody){
|
||||
if(!tri::HasPerMeshAttribute(mesh.cm, "physicsID"))
|
||||
MeshIterator entry = m_registeredMeshes.find(&mesh);
|
||||
if(entry == m_registeredMeshes.end())
|
||||
return;
|
||||
|
||||
MeshIndex index = tri::Allocator<CMeshO>::GetPerMeshAttribute<unsigned int>(mesh.cm, "physicsID");
|
||||
if(!isRigidBody && entry->second->body != 0){ // This mesh was registered as a rigid body
|
||||
dBodyDestroy(entry->second->body);
|
||||
entry->second->body = 0;
|
||||
}else if(isRigidBody && entry->second->body == 0){ // This mesh was registered as part of the scenery
|
||||
entry->second->body = dBodyCreate(m_world);
|
||||
dGeomSetBody(entry->second->geom, entry->second->body);
|
||||
|
||||
if(!isRigidBody && m_registeredMeshes[index()].second->body != 0){ // This mesh was registered as a rigid body
|
||||
dBodyDestroy(m_registeredMeshes[index()].second->body);
|
||||
m_registeredMeshes[index()].second->body = 0;
|
||||
}else if(isRigidBody && m_registeredMeshes[index()].second->body == 0){ // This mesh was registered as part of the scenery
|
||||
m_registeredMeshes[index()].second->body = dBodyCreate(m_world);
|
||||
dGeomSetBody(m_registeredMeshes[index()].second->geom, m_registeredMeshes[index()].second->body);
|
||||
|
||||
dMass* mass = &m_registeredMeshes[index()].second->mass;
|
||||
dMassSetTrimesh(mass, 1.0f, m_registeredMeshes[index()].second->geom);
|
||||
dMass* mass = &entry->second->mass;
|
||||
dMassSetTrimesh(mass, 1.0f, entry->second->geom);
|
||||
if(mass->mass < 0) throw ODEInvalidMeshException();
|
||||
mass->mass = 5;
|
||||
|
||||
dReal centerOfMass[3] = { mass->c[0], mass->c[1], mass->c[2] };
|
||||
dMassTranslate(&m_registeredMeshes[index()].second->mass, -centerOfMass[0], -centerOfMass[1], -centerOfMass[2]);
|
||||
dBodySetMass(m_registeredMeshes[index()].second->body, &m_registeredMeshes[index()].second->mass);
|
||||
dBodySetPosition(m_registeredMeshes[index()].second->body, m_registeredMeshes[index()].second->centerOfMass[0], m_registeredMeshes[index()].second->centerOfMass[1], m_registeredMeshes[index()].second->centerOfMass[2]);
|
||||
dMassTranslate(&entry->second->mass, -centerOfMass[0], -centerOfMass[1], -centerOfMass[2]);
|
||||
dBodySetMass(entry->second->body, &entry->second->mass);
|
||||
dBodySetPosition(entry->second->body, entry->second->centerOfMass[0], entry->second->centerOfMass[1], entry->second->centerOfMass[2]);
|
||||
}
|
||||
}
|
||||
|
||||
void ODEFacade::updateTransform(){
|
||||
for(MeshContainer::iterator i = m_registeredMeshes.begin(); i != m_registeredMeshes.end(); i++){
|
||||
const dReal* position = 0;
|
||||
const dReal* rotation = 0;
|
||||
if(i->second->body == 0)
|
||||
return;
|
||||
|
||||
if(i->second->body != 0){
|
||||
position = dBodyGetPosition(i->second->body);
|
||||
rotation = dBodyGetRotation(i->second->body);
|
||||
}else{
|
||||
position = dGeomGetPosition(i->second->geom);
|
||||
rotation = dGeomGetRotation(i->second->geom);
|
||||
}
|
||||
const dReal* position = dBodyGetPosition(i->second->body);
|
||||
const dReal* rotation = dBodyGetRotation(i->second->body);
|
||||
|
||||
i->first->cm.Tr[0][0] = rotation[0];
|
||||
i->first->cm.Tr[0][1] = rotation[1];
|
||||
@ -173,7 +172,7 @@ void ODEFacade::collisionCallback(dGeomID o1, dGeomID o2){
|
||||
|
||||
for(int i = 0; i < m_contacts.size(); i++){
|
||||
m_contacts[i].surface.mode = dContactBounce;
|
||||
m_contacts[i].surface.mu = 0.5;
|
||||
m_contacts[i].surface.mu = m_friction;
|
||||
m_contacts[i].surface.bounce = m_bounciness;
|
||||
m_contacts[i].surface.bounce_vel = 0.1;
|
||||
}
|
||||
@ -186,22 +185,13 @@ void ODEFacade::collisionCallback(dGeomID o1, dGeomID o2){
|
||||
}
|
||||
|
||||
vcg::Matrix44f ODEFacade::getTransformationMatrix(MeshModel& mesh){
|
||||
if(!tri::HasPerMeshAttribute(mesh.cm, "physicsID"))
|
||||
MeshIterator entry = m_registeredMeshes.find(&mesh);
|
||||
if(entry == m_registeredMeshes.end() || entry->second->body == 0)
|
||||
return mesh.cm.Tr;
|
||||
|
||||
MeshIndex index = tri::Allocator<CMeshO>::GetPerMeshAttribute<unsigned int>(mesh.cm, "physicsID");
|
||||
|
||||
vcg::Matrix44f matrix;
|
||||
const dReal* position = 0;
|
||||
const dReal* rotation = 0;
|
||||
|
||||
if(m_registeredMeshes[index()].second->body != 0){
|
||||
position = dBodyGetPosition(m_registeredMeshes[index()].second->body);
|
||||
rotation = dBodyGetRotation(m_registeredMeshes[index()].second->body);
|
||||
}else{
|
||||
position = dGeomGetPosition(m_registeredMeshes[index()].second->geom);
|
||||
rotation = dGeomGetRotation(m_registeredMeshes[index()].second->geom);
|
||||
}
|
||||
const dReal* position = dBodyGetPosition(entry->second->body);
|
||||
const dReal* rotation = dBodyGetRotation(entry->second->body);
|
||||
|
||||
matrix[0][0] = rotation[0];
|
||||
matrix[0][1] = rotation[1];
|
||||
@ -221,7 +211,7 @@ vcg::Matrix44f ODEFacade::getTransformationMatrix(MeshModel& mesh){
|
||||
matrix[3][3] = 1.f;
|
||||
|
||||
vcg::Matrix44f m;
|
||||
m.SetTranslate(-m_registeredMeshes[index()].second->centerOfMass[0], -m_registeredMeshes[index()].second->centerOfMass[1], -m_registeredMeshes[index()].second->centerOfMass[2]);
|
||||
m.SetTranslate(-entry->second->centerOfMass[0], -entry->second->centerOfMass[1], -entry->second->centerOfMass[2]);
|
||||
|
||||
return matrix * m;
|
||||
}
|
||||
@ -237,3 +227,7 @@ void ODEFacade::setMaxContacts(int contacts){
|
||||
void ODEFacade::setBounciness(float bounciness){
|
||||
m_bounciness = bounciness;
|
||||
}
|
||||
|
||||
void ODEFacade::setFriction(float friction){
|
||||
m_friction = friction;
|
||||
}
|
||||
|
||||
@ -5,15 +5,22 @@
|
||||
#ifndef ODE_FACADE_H
|
||||
#define ODE_FACADE_H
|
||||
|
||||
#include "PhysicsEngineFacade.h"
|
||||
|
||||
#include <vcg/complex/trimesh/allocate.h>
|
||||
#include <vcg/math/matrix44.h>
|
||||
#include <common/meshmodel.h>
|
||||
|
||||
#include <ode/ode.h>
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <exception>
|
||||
|
||||
class ODEFacade : public PhysicsEngineFacade{
|
||||
class ODEInvalidMeshException : public std::exception{
|
||||
public:
|
||||
const char* what() const throw(){
|
||||
return "Incorrect mesh: dynamic meshes can't have borders or a negative mass (check normals)!";
|
||||
}
|
||||
};
|
||||
|
||||
class ODEFacade{
|
||||
public:
|
||||
ODEFacade();
|
||||
|
||||
@ -27,6 +34,7 @@ public:
|
||||
virtual void setIterations(int iterations);
|
||||
virtual void setMaxContacts(int contacts);
|
||||
virtual void setBounciness(float bounciness);
|
||||
virtual void setFriction(float friction);
|
||||
|
||||
virtual void integrate(float step);
|
||||
virtual void clear(MeshDocument& md);
|
||||
@ -56,15 +64,17 @@ protected:
|
||||
dTriIndex (*indices)[3];
|
||||
};
|
||||
|
||||
typedef std::vector<std::pair<MeshModel*, ODEMesh*> > MeshContainer;
|
||||
typedef CMeshO::PerMeshAttributeHandle<unsigned int> MeshIndex;
|
||||
typedef std::map<MeshModel*, ODEMesh*> MeshContainer;
|
||||
typedef MeshContainer::iterator MeshIterator;
|
||||
|
||||
static void collisionCallback(void* data, dGeomID o1, dGeomID o2);
|
||||
void collisionCallback(dGeomID o1, dGeomID o2);
|
||||
bool hasBorders(MeshModel& mesh);
|
||||
|
||||
//This class is a monostate
|
||||
static bool m_initialized;
|
||||
static float m_bounciness;
|
||||
static float m_friction;
|
||||
|
||||
static dWorldID m_world;
|
||||
static dSpaceID m_space;
|
||||
@ -72,6 +82,6 @@ protected:
|
||||
static dJointGroupID m_contactGroup;
|
||||
|
||||
static MeshContainer m_registeredMeshes;
|
||||
};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -10,7 +10,7 @@ using namespace std;
|
||||
|
||||
int RandomDropFilter::m_filterType = -1;
|
||||
|
||||
RandomDropFilter::RandomDropFilter() : m_randomMesh(0), m_dropRate(-1), m_distance(-1), m_bboxUnit(false){
|
||||
RandomDropFilter::RandomDropFilter() : m_randomMesh(0), m_dropRate(-1), m_distance(-1){
|
||||
MeshSubFilter::m_currentFilterType += 1;
|
||||
m_filterType = MeshSubFilter::m_currentFilterType;
|
||||
}
|
||||
@ -18,20 +18,17 @@ RandomDropFilter::RandomDropFilter() : m_randomMesh(0), m_dropRate(-1), m_distan
|
||||
void RandomDropFilter::initParameterSet(QAction* action,MeshDocument& md, RichParameterSet & par){
|
||||
DynamicMeshSubFilter::initParameterSet(action, md, par);
|
||||
par.addParam(new RichMesh("randomMesh", 0, &md, "Random mesh", "This mesh will be randomly spawned in the scene"));
|
||||
par.addParam(new RichFloat("distance", 1.0f, "Random spawn radius", "The object will spawn in a random position contained in the specified radius"));
|
||||
par.addParam(new RichBool("bboxUnit", true, "Use bounding box units", "If true the random spawn radius will be computed in bounding box units"));
|
||||
par.addParam(new RichFloat("dropRate", 0.5, "Drop rate (sec)", "The drop rate of the filler mesh in seconds"));
|
||||
par.addParam(new RichAbsPerc("distance",md.bbox().Diag()*0.1,0,md.bbox().Diag(),"Random spawn radius", "The object will spawn in a random position contained in the specified radius"));
|
||||
|
||||
}
|
||||
|
||||
bool RandomDropFilter::applyFilter(QAction* filter, MeshDocument &md, RichParameterSet& par, vcg::CallBackPos* cb){
|
||||
if(md.size() < 2 || par.getMesh("randomMesh") == 0 || par.getMesh("randomMesh")->fileName.find("randomDropMesh") == 0 || par.getFloat("dropRate") < 0)
|
||||
return false;
|
||||
DynamicMeshSubFilter::applyFilter(filter, md, par, cb);
|
||||
|
||||
if(par.getFloat("dropRate") == 0)
|
||||
return true;
|
||||
|
||||
DynamicMeshSubFilter::applyFilter(filter, md, par, cb);
|
||||
|
||||
int currentStep = par.getDynamicFloat("timeline") / 100 * m_steps;
|
||||
int randomObjects = m_seconds*m_dropRate;
|
||||
int currentRandomObject = md.size() - randomObjects + currentStep/(m_fps/m_dropRate);
|
||||
@ -48,20 +45,26 @@ bool RandomDropFilter::applyFilter(QAction* filter, MeshDocument &md, RichParame
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RandomDropFilter::parametersAreNotCorrect(MeshDocument& md, RichParameterSet& par){
|
||||
return DynamicMeshSubFilter::parametersAreNotCorrect(md, par) || md.size() < 2 || par.getMesh("randomMesh") == 0 || par.getMesh("randomMesh")->fileName.find("randomDropMesh") == 0 || par.getFloat("dropRate") < 0;
|
||||
}
|
||||
|
||||
void RandomDropFilter::initialize(MeshDocument& md, RichParameterSet& par, vcg::CallBackPos* cb){
|
||||
DynamicMeshSubFilter::initialize(md, par, cb);
|
||||
|
||||
if(cb != 0) (*cb)(0, "Physics pre-renderization of the scene started...");
|
||||
|
||||
static float gravity[3] = {0.0f, -9.8f, 0.0f};
|
||||
float gravity[3] = {0.0f, m_gravity, 0.0f};
|
||||
m_engine.clear(md);
|
||||
m_engine.setGlobalForce(gravity);
|
||||
m_engine.setIterations(m_iterations);
|
||||
m_engine.setMaxContacts(m_contacts);
|
||||
m_engine.setBounciness(m_bounciness);
|
||||
m_engine.setFriction(m_friction);
|
||||
|
||||
srand((unsigned)time(0));
|
||||
int randomObjects = m_seconds*m_dropRate;
|
||||
int spawnInterval = m_fps / m_dropRate;
|
||||
m_steps = m_seconds * m_fps;
|
||||
|
||||
foreach(MeshModel *mesh, md.meshList){
|
||||
@ -69,14 +72,15 @@ void RandomDropFilter::initialize(MeshDocument& md, RichParameterSet& par, vcg::
|
||||
md.delMesh(mesh);
|
||||
}
|
||||
|
||||
for(int i = 0; i < randomObjects; i++)
|
||||
addRandomObject(md, i);
|
||||
|
||||
for(int i = 0; i < md.size() - randomObjects; i++){
|
||||
int meshes = md.size();
|
||||
for(int i = 0; i < md.size(); i++){
|
||||
if(m_randomMesh != md.getMesh(i))
|
||||
m_engine.registerTriMesh(*md.getMesh(i), true);
|
||||
}
|
||||
|
||||
for(int i = 0; i < randomObjects; i++)
|
||||
addRandomObject(md, i);
|
||||
|
||||
m_layersTrans.clear();
|
||||
m_layersTrans.resize(md.size());
|
||||
|
||||
@ -87,10 +91,8 @@ void RandomDropFilter::initialize(MeshDocument& md, RichParameterSet& par, vcg::
|
||||
for(int i = 0; i <= m_steps; i++){
|
||||
if(cb != 0) (*cb)(98.f*i/m_steps, "Computing...");
|
||||
|
||||
int currentRndObject = md.size() - randomObjects + i/(m_fps/m_dropRate);
|
||||
|
||||
if(i != 0 && i % int(m_fps/m_dropRate) == 0)
|
||||
m_engine.registerTriMesh(*md.getMesh(currentRndObject - 1), false);
|
||||
if(i != 0 && i % spawnInterval == 0)
|
||||
m_engine.registerTriMesh(*md.getMesh(meshes++), false);
|
||||
|
||||
for(int j = 0; j < md.size(); j++){
|
||||
m_layersTrans[j].push_back(m_engine.getTransformationMatrix(*md.getMesh(j)));
|
||||
@ -107,18 +109,15 @@ void RandomDropFilter::initialize(MeshDocument& md, RichParameterSet& par, vcg::
|
||||
}
|
||||
|
||||
void RandomDropFilter::addRandomObject(MeshDocument& md, int meshID){
|
||||
float multiplier = m_bboxUnit ? m_randomMesh->cm.bbox.Diag() : 1.0f;
|
||||
float distance = m_distance*multiplier;
|
||||
|
||||
ostringstream meshName;
|
||||
meshName << "randomDropMesh" << meshID;
|
||||
MeshModel* meshCopy = md.addNewMesh(meshName.str().c_str());
|
||||
vcg::tri::Append<CMeshO,CMeshO>::Mesh(meshCopy->cm, m_randomMesh->cm, false, true);
|
||||
meshCopy->cm.Tr = m_randomMesh->cm.Tr;
|
||||
|
||||
float x = meshCopy->cm.Tr.GetColumn3(3).X() + distance/2.0f - static_cast<float>(rand())/RAND_MAX*distance;
|
||||
float y = meshCopy->cm.Tr.GetColumn3(3).Y() + distance/2.0f - static_cast<float>(rand())/RAND_MAX*distance;
|
||||
float z = meshCopy->cm.Tr.GetColumn3(3).Z() + distance/2.0f - static_cast<float>(rand())/RAND_MAX*distance;
|
||||
float x = meshCopy->cm.Tr.GetColumn3(3).X() + m_distance/2.0f - static_cast<float>(rand())/RAND_MAX*m_distance;
|
||||
float y = meshCopy->cm.Tr.GetColumn3(3).Y() + m_distance/2.0f - static_cast<float>(rand())/RAND_MAX*m_distance;
|
||||
float z = meshCopy->cm.Tr.GetColumn3(3).Z() + m_distance/2.0f - static_cast<float>(rand())/RAND_MAX*m_distance;
|
||||
|
||||
meshCopy->cm.Tr.SetColumn(3, vcg::Point3f(x, y, z));
|
||||
meshCopy->visible = false;
|
||||
@ -127,15 +126,13 @@ void RandomDropFilter::addRandomObject(MeshDocument& md, int meshID){
|
||||
bool RandomDropFilter::configurationHasChanged(MeshDocument& md, RichParameterSet& par){
|
||||
bool changed = DynamicMeshSubFilter::configurationHasChanged(md, par) ||
|
||||
m_randomMesh != par.getMesh("randomMesh") ||
|
||||
m_distance != par.getFloat("distance") ||
|
||||
m_distance != par.getAbsPerc("distance") ||
|
||||
m_dropRate != par.getFloat("dropRate") ||
|
||||
m_bboxUnit != par.getBool("bboxUnit") ||
|
||||
m_currentFilterType != m_filterType;
|
||||
|
||||
m_randomMesh = par.getMesh("randomMesh");
|
||||
m_distance = par.getFloat("distance");
|
||||
m_distance = par.getAbsPerc("distance");
|
||||
m_dropRate = par.getFloat("dropRate");
|
||||
m_bboxUnit = par.getBool("bboxUnit");
|
||||
m_currentFilterType = m_filterType;
|
||||
|
||||
return changed;
|
||||
|
||||
@ -14,6 +14,7 @@ public:
|
||||
|
||||
virtual void initParameterSet(QAction* action,MeshDocument& md, RichParameterSet & par);
|
||||
virtual bool applyFilter(QAction* filter, MeshDocument &md, RichParameterSet& par, vcg::CallBackPos* cb);
|
||||
virtual bool parametersAreNotCorrect(MeshDocument& md, RichParameterSet& par);
|
||||
|
||||
protected:
|
||||
virtual void initialize(MeshDocument&, RichParameterSet&, vcg::CallBackPos* cb);
|
||||
@ -24,7 +25,6 @@ private:
|
||||
MeshModel* m_randomMesh;
|
||||
float m_dropRate;
|
||||
float m_distance;
|
||||
bool m_bboxUnit;
|
||||
ODEFacade m_engine;
|
||||
|
||||
static int m_filterType;
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include <vcg/complex/trimesh/append.h>
|
||||
#include <vcg/complex/trimesh/inertia.h>
|
||||
#include <vcg/complex/trimesh/clean.h>
|
||||
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
@ -23,25 +24,35 @@ void RandomFillFilter::initParameterSet(QAction* action,MeshDocument& md, RichPa
|
||||
par.addParam(new RichMesh("container", 0, &md, "Container mesh", "This mesh will act as a container for the filling mesh"));
|
||||
par.addParam(new RichMesh("filler", 0, &md, "Filler mesh", "The container mesh will be filled with this mesh"));
|
||||
par.addParam(new RichFloat("factor", 0.5, "Volume ratio factor", "The ratio between the container and the filler object will be multiplied by this factor. The volume ratio determines the number of filling objects to be spawn."));
|
||||
par.addParam(new RichBool("useRandomVertices", true, "Random spawn points", "If true the filling objects will spawn at random positions in the container mesh instead of being spawn at the center of mass"));
|
||||
par.addParam(new RichFloat("seconds", 1, "Simulation interval (sec)", "Physics simulation interval in seconds"));
|
||||
par.addParam(new RichBool("flipNormal", false, "Flip container normals", "If true the container normals will be flipped."));
|
||||
}
|
||||
|
||||
bool RandomFillFilter::applyFilter(QAction* filter, MeshDocument &md, RichParameterSet& par, vcg::CallBackPos* cb){
|
||||
if(md.size() < 2 || par.getMesh("container") == 0 || par.getMesh("container") == par.getMesh("filler") || par.getInt("fps") <= 0 || par.getInt("iterations") <= 0 || par.getInt("contacts") <= 0 || par.getFloat("bounciness") < 0.f || par.getFloat("bounciness") > 1.f || par.getFloat("factor") < 0.f || par.getFloat("factor") > 1.f)
|
||||
if(parametersAreNotCorrect(md, par))
|
||||
return false;
|
||||
|
||||
MeshSubFilter::initialize(md, par, cb);
|
||||
if(cb != 0) (*cb)(0, "Physics renderization of the scene started...");
|
||||
|
||||
MeshModel* container = par.getMesh("container");
|
||||
MeshModel* filler = par.getMesh("filler");
|
||||
int fillOffset = md.size();
|
||||
float gravity[3] = {0.0f, 0.0f, 0.0f};
|
||||
|
||||
if(par.getBool("flipNormal")){
|
||||
vcg::tri::Clean<CMeshO>::FlipMesh(container->cm);
|
||||
tri::UpdateNormals<CMeshO>::PerVertexNormalizedPerFace(container->cm);
|
||||
container->clearDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
|
||||
par.setValue("flipNormal", BoolValue(false)); // Why does it not work??
|
||||
}
|
||||
|
||||
static float gravity[3] = {0.0f, -9.8f, 0.0f};
|
||||
m_engine.clear(md);
|
||||
m_engine.setGlobalForce(gravity);
|
||||
m_engine.setIterations(par.getInt("iterations"));
|
||||
m_engine.setMaxContacts(par.getInt("contacts"));
|
||||
m_engine.setBounciness(par.getFloat("bounciness"));
|
||||
m_engine.setFriction(par.getFloat("friction"));
|
||||
m_engine.registerTriMesh(*container, true);
|
||||
|
||||
srand((unsigned)time(0));
|
||||
@ -56,26 +67,26 @@ bool RandomFillFilter::applyFilter(QAction* filter, MeshDocument &md, RichParame
|
||||
int objects = abs(inertiaContainer.Mass()/inertiaFiller.Mass())*par.getFloat("factor");
|
||||
filler->cm.Tr.SetColumn(3, - inertiaFiller.CenterOfMass());
|
||||
|
||||
if(par.getBool("useRandomVertices")){
|
||||
for(int i = 0; i < objects; i++){
|
||||
if(cb != 0) (*cb)(50.f*i/objects, "Computing...");
|
||||
addRandomObject(md, filler, getRandomOrigin(par), i);
|
||||
m_engine.registerTriMesh(*md.getMesh(fillOffset++));
|
||||
}
|
||||
|
||||
for(int j = 0; j < par.getInt("fps"); j++){
|
||||
if(cb != 0) (*cb)(50 + 48.f*j/par.getInt("fps"), "Computing...");
|
||||
//Restore old generated meshes
|
||||
int restoredMeshes = 0;
|
||||
for(int i = 0; i < md.size(); i++){
|
||||
if(md.getMesh(i)->fileName.find("randomFillMesh") == 0){
|
||||
m_engine.registerTriMesh(*md.getMesh(i));
|
||||
restoredMeshes++;
|
||||
m_engine.integrate(1.0f/par.getInt("fps"));
|
||||
}
|
||||
}else{
|
||||
for(int i = 0; i < objects; i++){
|
||||
if(cb != 0) (*cb)(98.f*i/objects, "Computing...");
|
||||
addRandomObject(md, filler, inertiaContainer.CenterOfMass(), i);
|
||||
m_engine.registerTriMesh(*md.getMesh(fillOffset++));
|
||||
}
|
||||
|
||||
for(int j = 0; j < par.getInt("fps")/2; j++)
|
||||
m_engine.integrate(1.0f/par.getInt("fps"));
|
||||
}
|
||||
for(int i = 0; i < objects; i++){
|
||||
if(cb != 0) (*cb)(50.f*i/objects, "Computing...");
|
||||
addRandomObject(md, filler, getRandomOrigin(par), restoredMeshes + i);
|
||||
m_engine.registerTriMesh(*md.getMesh(fillOffset++));
|
||||
m_engine.integrate(1.0f/par.getInt("fps"));
|
||||
}
|
||||
|
||||
for(int j = 0; j < par.getFloat("seconds") * par.getInt("fps"); j++){
|
||||
if(cb != 0) (*cb)(50 + 48.f*j/par.getInt("fps"), "Computing...");
|
||||
m_engine.integrate(1.0f/par.getInt("fps"));
|
||||
}
|
||||
|
||||
m_engine.updateTransform();
|
||||
@ -85,8 +96,12 @@ bool RandomFillFilter::applyFilter(QAction* filter, MeshDocument &md, RichParame
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RandomFillFilter::parametersAreNotCorrect(MeshDocument& md, RichParameterSet& par){
|
||||
return md.size() < 2 || par.getMesh("container") == 0 || par.getMesh("container") == par.getMesh("filler") || par.getInt("fps") <= 0 || par.getInt("iterations") <= 0 || par.getInt("contacts") <= 0 || par.getFloat("bounciness") < 0.f || par.getFloat("bounciness") > 1.f || par.getFloat("factor") < 0.f || par.getFloat("factor") > 1.f;
|
||||
}
|
||||
|
||||
vcg::Point3<float> RandomFillFilter::getRandomOrigin(RichParameterSet& par){
|
||||
int randomVertex = static_cast<float>(rand())/RAND_MAX*(par.getMesh("container")->cm.vert.size() - 1);
|
||||
int randomVertex = float(rand())/RAND_MAX*(par.getMesh("container")->cm.vert.size() - 1);
|
||||
CVertexO& vertex = par.getMesh("container")->cm.vert[randomVertex];
|
||||
return vertex.P() + (vertex.N() * par.getMesh("filler")->cm.bbox.Diag());
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ public:
|
||||
|
||||
virtual void initParameterSet(QAction* action,MeshDocument& md, RichParameterSet & par);
|
||||
virtual bool applyFilter(QAction* filter, MeshDocument &md, RichParameterSet& par, vcg::CallBackPos* cb);
|
||||
virtual bool parametersAreNotCorrect(MeshDocument& md, RichParameterSet& par);
|
||||
|
||||
protected:
|
||||
virtual void addRandomObject(MeshDocument& md, MeshModel* filler, const vcg::Point3<float>& origin, int meshID);
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
#include <QtGui>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <exception>
|
||||
|
||||
using namespace std;
|
||||
using namespace vcg;
|
||||
|
||||
@ -63,25 +65,33 @@ void FilterPhysics::initParameterSet(QAction* action,MeshDocument& md, RichParam
|
||||
}
|
||||
|
||||
bool FilterPhysics::applyFilter(QAction* action, MeshDocument &md, RichParameterSet& par, vcg::CallBackPos* cb){
|
||||
bool ret = true;
|
||||
try{
|
||||
bool ret = true;
|
||||
|
||||
switch(ID(action)){
|
||||
case FP_PHYSICS_GRAVITY:
|
||||
ret = m_gravityFilter.applyFilter(action, md, par, cb);
|
||||
break;
|
||||
case FP_PHYSICS_RNDDROP:
|
||||
ret = m_rndDropFilter.applyFilter(action, md, par, cb);
|
||||
break;
|
||||
case FP_PHYSICS_RNDFILL:
|
||||
ret = m_rndFillFilter.applyFilter(action, md, par, cb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
switch(ID(action)){
|
||||
case FP_PHYSICS_GRAVITY:
|
||||
ret = m_gravityFilter.applyFilter(action, md, par, cb);
|
||||
break;
|
||||
case FP_PHYSICS_RNDDROP:
|
||||
ret = m_rndDropFilter.applyFilter(action, md, par, cb);
|
||||
break;
|
||||
case FP_PHYSICS_RNDFILL:
|
||||
ret = m_rndFillFilter.applyFilter(action, md, par, cb);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(!ret){
|
||||
QMessageBox::critical(0, QString("Error"), QString("Invalid filter configuration: check your parameters"));
|
||||
return false;
|
||||
}
|
||||
}catch(std::exception& ex){
|
||||
MeshSubFilter::clearLastAppliedFilter();
|
||||
QMessageBox::critical(0, QString("Error"), ex.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!ret)
|
||||
QMessageBox::critical(0, QString("Error"), QString("Invalid filter configuration parameters"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -31,8 +31,8 @@ class FilterPhysics : public QObject, public MeshFilterInterface
|
||||
virtual QString filterName(FilterIDType filter) const;
|
||||
virtual QString filterInfo(FilterIDType filter) const;
|
||||
|
||||
virtual int getRequirements(QAction*){return MeshModel::MM_FACEVERT | MeshModel::MM_FACENORMAL | MeshModel::MM_VERTNORMAL; }
|
||||
virtual int postCondition( QAction* ) const{return MeshModel::MM_FACENORMAL; /*MeshModel::MM_TRANSFMATRIX; */}
|
||||
virtual int getRequirements(QAction*){return MeshModel::MM_FACEVERT | MeshModel::MM_FACENORMAL | MeshModel::MM_VERTNORMAL | MeshModel::MM_FACEFACETOPO; }
|
||||
virtual int postCondition( QAction* ) const{return MeshModel::MM_FACENORMAL | MeshModel::MM_TRANSFMATRIX;}
|
||||
|
||||
virtual bool autoDialog(QAction*) {return true;}
|
||||
virtual void initParameterSet(QAction*, MeshDocument&, RichParameterSet&);
|
||||
|
||||
@ -2,7 +2,6 @@ include (../../shared.pri)
|
||||
DEFINES += dSINGLE
|
||||
HEADERS = filter_physics.h \
|
||||
ODEFacade.h \
|
||||
PhysicsEngineFacade.h \
|
||||
MeshSubFilter.h \
|
||||
GravitySubFilter.h \
|
||||
RandomDropFilter.h \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user