Compare commits

...

70 Commits

Author SHA1 Message Date
39dc956f59 Merge branch 'master' into soc-2013-rigid_body_sim
Conflicts:
	intern/rigidbody/CMakeLists.txt
	release/datafiles/splash.png
	source/blender/editors/space_view3d/drawobject.c
	source/blender/makesdna/DNA_view3d_types.h
2013-11-23 17:17:12 +01:00
5d5176095e svn merge -r60422:60726 ^/trunk/blender 2013-10-13 11:41:41 +00:00
bcbf976b48 rigidbody: Code cleanup
Remove duplicate code.
2013-10-02 19:59:55 +00:00
8259ccd508 rigidbody: Try to use old collision shape if creating new one fails
Switching to box in that case isn't very nice behaviour and should be
avoided if possible.
2013-09-30 14:40:03 +00:00
da453676ce rigidbody: Add impulse threshold for collision based activation 2013-09-30 12:59:53 +00:00
bfb34b22f7 rigidbody: Only handle activation when collision was detected
Somehow missed to add this before.
2013-09-29 14:24:20 +00:00
e4f5cfc508 svn merge -r60273:60421 ^/trunk/blender 2013-09-29 13:57:59 +00:00
2bc0422e08 rigidbody: Don't handle collision after hitting a trigger 2013-09-22 14:42:25 +00:00
ce510086fc rigidbody: Code cleanup
Make functions private that are only used internally.
Also remove a nested if statement.
2013-09-22 13:49:59 +00:00
a6b95d34e2 rigidbody: Code cleanup
Avoid mixing bool and int.
2013-09-22 13:49:57 +00:00
00abe28109 rigidbody: Flag bodies for validation when changing shape
This fixes a pretty old crash that occurs when changing the collision
shape to a mesh shape during simulation.

Thanks to Thomas Beck (plasmasolutions) for the report.
2013-09-22 13:22:52 +00:00
e3c285582c rigidbody: Fix crash switching to a mesh shape during simulation while using deformation
Thanks to Thomas Beck (plasmasolutions) for the report.
2013-09-22 11:32:26 +00:00
9c5c60c2a3 rigidbody: Update 3D view when changing the shape via operator 2013-09-22 10:25:56 +00:00
414329815b rigidbody: Only allow static-static collision when trigger is kinematic
This way passive object don't activate passive objects when using
activation on collision.
2013-09-22 09:56:03 +00:00
b10c869faf rigidbody: Don't try to deform shapes if we don't have a derived mesh 2013-09-22 09:27:26 +00:00
a98a32e6c8 rigidbody: Abort mesh shape creation when we can't get a derived mesh
Would only assert before, now just return.

Thanks to Thomas Beck (plasmasolutions) for report.
2013-09-22 09:02:38 +00:00
46b995e691 rigidbody: Allow deformation option to be animated 2013-09-22 06:48:57 +00:00
22a3f8b751 rigidbody: Fix crash with meshes that have both quads and tirs/ngons
Triangles weren't counted right, silly copy paste mistake.
2013-09-21 21:26:30 +00:00
c22a365b1b rigidbody: Fix activation not working with passive objects as triggers
Need to allow static-static collisions in this case, since deactivated
bodies are static.
2013-09-21 05:12:09 +00:00
f6d12c86db rigidbody: Fix conflict between collision and time based activation
Now do more thorough check.
2013-09-21 05:12:08 +00:00
8ce4109597 rigidbody: Fix activation on collision when both bodies were deactivated
Missed checking for both members of collision pair.
2013-09-21 05:12:07 +00:00
6b20b94953 rigidbody: Add activation based on time
Time is specified in seconds.
2013-09-21 05:12:05 +00:00
d1e5eb4a1f rigidbody: Fix effectors getting weaker/stronger with different fps
Effectors weaken the force based on fps, for bullet we need to keep it
constant regardless of render fps.
To stay relatively backwards compatible the force will stay the same
when using 24 fps since it's blender's default.
2013-09-21 05:12:03 +00:00
5fecbda461 rigidbody: Fix changing to a deforming collision shape during simulation 2013-09-21 05:12:02 +00:00
7b281b3ae4 drawobject: Add option to disable physics visualization
Right now this only disables rigid body visualizaion.
TODO: Disable visualizaion for other simulations as well.
2013-09-21 05:12:00 +00:00
b2388aa8e3 rigidbody: Update 3d view when changing collision shape 2013-09-21 05:11:58 +00:00
817f08be38 drawobject: Draw game engine collision bounds in edit mode
It's usefull to see how the collision shape will look like while editing
the mesh.
Also draw rigid body collision shape even if game engine bounds are
drawn.
2013-09-21 05:11:57 +00:00
9088d62702 rigidbody: Allow active rigid bodies to deform 2013-09-21 05:11:56 +00:00
40c8bf395d rigidbody: Allow triangle mesh shapes to deform during simulation
Only supported when using the "Deform" mesh source.
TODO: look into deforming active rigid bodies
2013-09-21 05:11:53 +00:00
094445f973 rigidbody: Use own structure to store mesh data for collision shapes
This gives us better access to the mesh data for collision shapes.
Also should be faster to create.
TODO: look into sharing at least vertex data between collision shape and
derived mesh.
2013-09-21 05:11:51 +00:00
f21f340185 rigidbody: Disable internal edge info
There is a conflict with using it and compound shapes at the same time.
Since we wrap all shapes in compounds, it has no effect.
2013-09-21 05:11:49 +00:00
59d22634e0 svn merge -r59869:60272 ^/trunk/blender 2013-09-20 20:25:07 +00:00
c6f3614329 rigidbody: Add effector weights for individual rigid bodies
There's a need for more fine grained control over how individual rigid
bodies are affected by force fields.
Having effector weights for both the world and bodies might be too much.
If so, we could drop it from the world and copy the world settings to
the body setting for old files.
2013-09-06 17:59:09 +00:00
bf2d4f55de rigidbody: Code cleanup
Remove some debug prints.
2013-09-06 17:59:07 +00:00
6cdc6bf60a rigidbody: UI cleanup
Split a row that was too long into two columns.
2013-09-06 17:59:05 +00:00
d911109fb4 rigidbody: Add internal edge info for triangle mesh shapes
This is necessary so that triangle edges don't create erroneous
collisions.

TODO: Fix issues when using compound shapes
2013-09-06 17:59:04 +00:00
c858206f75 rigidbody: Fix compiler warning 2013-09-06 17:59:03 +00:00
005ab5cbe4 rigidbody: Add activation types
Now users can specify how object can be activated.
Right now only two options work:
Collision: bodies are activated on collision with other bodies
Trigger: bodies are activated on collision with trigger objects

TODO: implement activation based on time.
2013-09-06 17:59:02 +00:00
ce726474e6 rigidbody: UI cleanup
Split Activation and Deactivation into separate columns.
Rename "Enable Deactivation" -> "Allow Deactivation".
"Deactivation" is still a little misleading, maybe we should use
"Sleeping" instead?
2013-09-06 17:59:00 +00:00
d1781c8f7e rigidbody: Add ghost objects
Ghost objects simply don't respond to collisions, mostly useful for
triggers for now.
The UI is getting messy now, will clean up later.
2013-09-06 17:58:58 +00:00
15aeb1d714 rigidbody: Improve object de-/activation
Now de don't use bullet's deactivation system.
Instead of activating bodies based on bonding boxes they're now
activated on actual collision.
Also, "Enable Deactivation" has a different meaning now. It's mostly
used to improve performance.
TODO: reflect that in the UI.
2013-09-06 17:58:56 +00:00
17accbd408 rigidbody: Allow trigger objects to respond to collisions
It's still desirable to have trigger object interacting with the
simulation in many cases.
Will add separate ghost objects later to allow for triggers that don't
collide.
2013-09-06 17:58:54 +00:00
3977df582d drawobject: Code cleanup
Get rid of some vector copying.
2013-09-06 17:58:53 +00:00
ac4dccec1d rigidbody: Add option to mark rigid bodies as collision triggers
Trigger object behave like normal rigid bodies but don't respond to
collisions.
2013-09-06 17:58:52 +00:00
942264da64 drawobject: Fix bounds drawing for game engine
In the game engine primitive collision shapes are always created around
the origin of the object.
So need to offset bounds in case the origin is not center of the object.
2013-09-06 17:58:50 +00:00
776a201fd7 drawobject: Fix sphere drawing
Now draw uniform sphere instead of ellipsoid.
2013-09-06 17:58:48 +00:00
a5ac14aab5 drawobject: Draw collision shapes when object has rigid body
This uses the regular bounds drawing like the game engine for now, which
is not always accurate.
Will fix next.
2013-09-06 17:58:47 +00:00
1d9ba24129 rigidbody: Use deformations for collision shapes by default 2013-09-06 17:58:46 +00:00
8e4890b536 rigidbody: Add option to choose mesh source for collision shapes
The options are:
Base: Base mesh
Deform: shape keys and deform modifiers
Final: All deformations and modifiers

It would be nice to have a way of specifying where exactly in the
modifier stack the collision shape is generated. However this is not
staight forward since the rigid body simulation is not part of the
modifier system and would require hacks to make it work.
2013-09-06 17:58:45 +00:00
c8ca998e2b svn merge -r59227:59228 ^/trunk/blender
Missed this in last merge.
2013-09-06 17:45:58 +00:00
36e6bddb5c svn merge -r59229:59868 ^/trunk/blender 2013-09-06 08:35:00 +00:00
df3974b6d1 Fix building with blenderplayer 2013-08-18 12:29:26 +00:00
57051902b5 rigidbody: Add convex decomposition collision shape
Uses HACD to break concave meshes into convex chunks and stores them in
a compound shape.

There is a lot of room for optimization. Right now performing convex
decomposition can be very slow for complex meshes.
2013-08-18 12:29:24 +00:00
4acb76734f rigidbody: Fix gimpact shape
Also forgot compound wrapper here
2013-08-18 12:29:22 +00:00
41e9166164 rigdibody: Don't free DerivedMesh when creating mesh shapes
It's not necessary since we don't create it ourselves now.
2013-08-18 12:29:21 +00:00
7331164531 svn merge -r58494:59227 ^/trunk/blender 2013-08-18 12:28:32 +00:00
6005ba52f5 Add HACD (Hierarchical Approximate Convex Decomposition) library
This is the version bundled with bullet.
We should probably use a more recent version but there are different
repositories out there, so we have to test first.
2013-07-22 07:20:37 +00:00
c4c2185850 rigidbody: Merge RB_body_get_position/orientation functions into one
Avoids unneeded calculations.
2013-07-22 07:20:32 +00:00
773b7bb673 rigidbody: Add support for compound shapes
Compounds are defined implicitly by the parenting hierarchy.

TODO: Take more one level of the hierarchy is taken into account when
creating compound shapes.
2013-07-22 07:20:30 +00:00
0a50b75fe5 rigidbody: Fix convex hull shape
Missed adding compound shape wrapper.
2013-07-22 07:20:28 +00:00
a475b5f702 rigidbody: Add custom center of mass for primitive shapes
Now the origin of the object is the center of mass for all collision
shapes.
To do that all shapes are now wrapped inside a compound shape.

TODO: fix istability with mesh shapes when using compounds, might be
bullet bug.
2013-07-22 07:20:27 +00:00
0866d5d2e2 svn merge -r57991:58488 ^/trunk/blender 2013-07-22 07:14:25 +00:00
c565541517 svn merge -r57985:57990 ^/trunk/blender 2013-07-04 10:16:22 +00:00
65d9a24db5 svn merge -r57643:57984 ^/trunk/blender 2013-07-04 06:20:01 +00:00
880fe69dc7 svn merge -r57524:57642 ^/trunk/blender 2013-06-21 18:18:37 +00:00
fbdf015c3a rigidbody: Avoid unnecessary reallocations when creating mesh shapes 2013-06-21 18:01:17 +00:00
c28e76cf3f rigidbody: Add debug drawing
This is very much a hack (crashes with big scenes), and will be removed
or at least rewritten in the future.
Use debug value 616 to enable.
2013-06-21 18:01:14 +00:00
f64bb323a8 rigidbody: Take deformations into account when creating collision shapes
TODO: Make sure ob->derivedDeform always esists.
2013-06-17 16:49:11 +00:00
c726312325 svn merge -r57394:57521 ^/trunk/blender 2013-06-17 16:01:37 +00:00
f131b583d6 gsoc 2013 branch soc-2013-rigid_body_sim 2013-06-12 04:04:41 +00:00
36 changed files with 5187 additions and 176 deletions

View File

@@ -35,6 +35,7 @@ if(WITH_BULLET)
if(NOT WITH_SYSTEM_BULLET)
add_subdirectory(bullet2)
endif()
add_subdirectory(HACD)
endif()
# now only available in a branch

47
extern/HACD/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,47 @@
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# The Original Code is Copyright (C) 2006, Blender Foundation
# All rights reserved.
#
# The Original Code is: all of this file.
#
# Contributor(s): Sergej Reich
#
# ***** END GPL LICENSE BLOCK *****
SET(SRC
hacdGraph.cpp
hacdHACD.cpp
hacdICHull.cpp
hacdManifoldMesh.cpp
hacdCircularList.h
hacdGraph.h
hacdHACD.h
hacdICHull.h
hacdManifoldMesh.h
hacdVector.h
hacdVersion.h
hacdCircularList.inl
hacdVector.inl
)
SET(INC
.
)
blender_add_lib(extern_hacd "${SRC}" "${INC}" "${INC_SYS}")

80
extern/HACD/hacdCircularList.h vendored Normal file
View File

@@ -0,0 +1,80 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef HACD_CIRCULAR_LIST_H
#define HACD_CIRCULAR_LIST_H
#include<stdlib.h>
#include "hacdVersion.h"
namespace HACD
{
//! CircularListElement class.
template < typename T > class CircularListElement
{
public:
T & GetData() { return m_data; }
const T & GetData() const { return m_data; }
CircularListElement<T> * & GetNext() { return m_next; }
CircularListElement<T> * & GetPrev() { return m_prev; }
const CircularListElement<T> * & GetNext() const { return m_next; }
const CircularListElement<T> * & GetPrev() const { return m_prev; }
//! Constructor
CircularListElement(const T & data) {m_data = data;}
CircularListElement(void){}
//! Destructor
~CircularListElement(void){}
private:
T m_data;
CircularListElement<T> * m_next;
CircularListElement<T> * m_prev;
CircularListElement(const CircularListElement & rhs);
};
//! CircularList class.
template < typename T > class CircularList
{
public:
CircularListElement<T> * & GetHead() { return m_head;}
const CircularListElement<T> * GetHead() const { return m_head;}
bool IsEmpty() const { return (m_size == 0);}
size_t GetSize() const { return m_size; }
const T & GetData() const { return m_head->GetData(); }
T & GetData() { return m_head->GetData();}
bool Delete() ;
bool Delete(CircularListElement<T> * element);
CircularListElement<T> * Add(const T * data = 0);
CircularListElement<T> * Add(const T & data);
bool Next();
bool Prev();
void Clear() { while(Delete());};
const CircularList& operator=(const CircularList& rhs);
//! Constructor
CircularList()
{
m_head = 0;
m_size = 0;
}
CircularList(const CircularList& rhs);
//! Destructor
virtual ~CircularList(void) {Clear();};
private:
CircularListElement<T> * m_head; //!< a pointer to the head of the circular list
size_t m_size; //!< number of element in the circular list
};
}
#include "hacdCircularList.inl"
#endif

163
extern/HACD/hacdCircularList.inl vendored Normal file
View File

@@ -0,0 +1,163 @@
#pragma once
#ifndef HACD_CIRCULAR_LIST_INL
#define HACD_CIRCULAR_LIST_INL
#include<stdlib.h>
#include "hacdVersion.h"
namespace HACD
{
template < typename T >
inline bool CircularList<T>::Delete(CircularListElement<T> * element)
{
if (!element)
{
return false;
}
if (m_size > 1)
{
CircularListElement<T> * next = element->GetNext();
CircularListElement<T> * prev = element->GetPrev();
delete element;
m_size--;
if (element == m_head)
{
m_head = next;
}
next->GetPrev() = prev;
prev->GetNext() = next;
return true;
}
else if (m_size == 1)
{
delete m_head;
m_size--;
m_head = 0;
return true;
}
else
{
return false;
}
}
template < typename T >
inline bool CircularList<T>::Delete()
{
if (m_size > 1)
{
CircularListElement<T> * next = m_head->GetNext();
CircularListElement<T> * prev = m_head->GetPrev();
delete m_head;
m_size--;
m_head = next;
next->GetPrev() = prev;
prev->GetNext() = next;
return true;
}
else if (m_size == 1)
{
delete m_head;
m_size--;
m_head = 0;
return true;
}
else
{
return false;
}
}
template < typename T >
inline CircularListElement<T> * CircularList<T>::Add(const T * data)
{
if (m_size == 0)
{
if (data)
{
m_head = new CircularListElement<T>(*data);
}
else
{
m_head = new CircularListElement<T>();
}
m_head->GetNext() = m_head->GetPrev() = m_head;
}
else
{
CircularListElement<T> * next = m_head->GetNext();
CircularListElement<T> * element = m_head;
if (data)
{
m_head = new CircularListElement<T>(*data);
}
else
{
m_head = new CircularListElement<T>;
}
m_head->GetNext() = next;
m_head->GetPrev() = element;
element->GetNext() = m_head;
next->GetPrev() = m_head;
}
m_size++;
return m_head;
}
template < typename T >
inline CircularListElement<T> * CircularList<T>::Add(const T & data)
{
const T * pData = &data;
return Add(pData);
}
template < typename T >
inline bool CircularList<T>::Next()
{
if (m_size == 0)
{
return false;
}
m_head = m_head->GetNext();
return true;
}
template < typename T >
inline bool CircularList<T>::Prev()
{
if (m_size == 0)
{
return false;
}
m_head = m_head->GetPrev();
return true;
}
template < typename T >
inline CircularList<T>::CircularList(const CircularList& rhs)
{
if (rhs.m_size > 0)
{
CircularListElement<T> * current = rhs.m_head;
do
{
current = current->GetNext();
Add(current->GetData());
}
while ( current != rhs.m_head );
}
}
template < typename T >
inline const CircularList<T>& CircularList<T>::operator=(const CircularList& rhs)
{
if (&rhs != this)
{
Clear();
if (rhs.m_size > 0)
{
CircularListElement<T> * current = rhs.m_head;
do
{
current = current->GetNext();
Add(current->GetData());
}
while ( current != rhs.m_head );
}
}
return (*this);
}
}
#endif

292
extern/HACD/hacdGraph.cpp vendored Normal file
View File

@@ -0,0 +1,292 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "hacdGraph.h"
namespace HACD
{
GraphEdge::GraphEdge()
{
m_convexHull = 0;
m_v1 = -1;
m_v2 = -1;
m_name = -1;
m_error = 0;
m_surf = 0;
m_perimeter = 0;
m_concavity = 0;
m_volume = 0;
m_deleted = false;
}
GraphVertex::GraphVertex()
{
m_convexHull = 0;
m_name = -1;
m_cc = -1;
m_error = 0;
m_surf = 0;
m_perimeter = 0;
m_concavity = 0;
m_volume = 0;
m_deleted = false;
}
bool GraphVertex::DeleteEdge(long name)
{
std::set<long>::iterator it = m_edges.find(name);
if (it != m_edges.end() )
{
m_edges.erase(it);
return true;
}
return false;
}
Graph::Graph()
{
m_nV = 0;
m_nE = 0;
m_nCCs = 0;
}
Graph::~Graph()
{
}
void Graph::Allocate(size_t nV, size_t nE)
{
m_nV = nV;
m_edges.reserve(nE);
m_vertices.resize(nV);
for(size_t i = 0; i < nV; i++)
{
m_vertices[i].m_name = static_cast<long>(i);
}
}
long Graph::AddVertex()
{
size_t name = m_vertices.size();
m_vertices.resize(name+1);
m_vertices[name].m_name = static_cast<long>(name);
m_nV++;
return static_cast<long>(name);
}
long Graph::AddEdge(long v1, long v2)
{
size_t name = m_edges.size();
m_edges.push_back(GraphEdge());
m_edges[name].m_name = static_cast<long>(name);
m_edges[name].m_v1 = v1;
m_edges[name].m_v2 = v2;
m_vertices[v1].AddEdge(static_cast<long>(name));
m_vertices[v2].AddEdge(static_cast<long>(name));
m_nE++;
return static_cast<long>(name);
}
bool Graph::DeleteEdge(long name)
{
if (name < static_cast<long>(m_edges.size()))
{
long v1 = m_edges[name].m_v1;
long v2 = m_edges[name].m_v2;
m_edges[name].m_deleted = true;
m_vertices[v1].DeleteEdge(name);
m_vertices[v2].DeleteEdge(name);
delete m_edges[name].m_convexHull;
m_edges[name].m_distPoints.clear();
m_edges[name].m_boudaryEdges.clear();
m_edges[name].m_convexHull = 0;
m_nE--;
return true;
}
return false;
}
bool Graph::DeleteVertex(long name)
{
if (name < static_cast<long>(m_vertices.size()))
{
m_vertices[name].m_deleted = true;
m_vertices[name].m_edges.clear();
m_vertices[name].m_ancestors = std::vector<long>();
delete m_vertices[name].m_convexHull;
m_vertices[name].m_distPoints.clear();
m_vertices[name].m_boudaryEdges.clear();
m_vertices[name].m_convexHull = 0;
m_nV--;
return true;
}
return false;
}
bool Graph::EdgeCollapse(long v1, long v2)
{
long edgeToDelete = GetEdgeID(v1, v2);
if (edgeToDelete >= 0)
{
// delete the edge (v1, v2)
DeleteEdge(edgeToDelete);
// add v2 to v1 ancestors
m_vertices[v1].m_ancestors.push_back(v2);
// add v2's ancestors to v1's ancestors
m_vertices[v1].m_ancestors.insert(m_vertices[v1].m_ancestors.begin(),
m_vertices[v2].m_ancestors.begin(),
m_vertices[v2].m_ancestors.end());
// update adjacency information
std::set<long> & v1Edges = m_vertices[v1].m_edges;
std::set<long>::const_iterator ed(m_vertices[v2].m_edges.begin());
std::set<long>::const_iterator itEnd(m_vertices[v2].m_edges.end());
long b = -1;
for(; ed != itEnd; ++ed)
{
if (m_edges[*ed].m_v1 == v2)
{
b = m_edges[*ed].m_v2;
}
else
{
b = m_edges[*ed].m_v1;
}
if (GetEdgeID(v1, b) >= 0)
{
m_edges[*ed].m_deleted = true;
m_vertices[b].DeleteEdge(*ed);
m_nE--;
}
else
{
m_edges[*ed].m_v1 = v1;
m_edges[*ed].m_v2 = b;
v1Edges.insert(*ed);
}
}
// delete the vertex v2
DeleteVertex(v2);
return true;
}
return false;
}
long Graph::GetEdgeID(long v1, long v2) const
{
if (v1 < static_cast<long>(m_vertices.size()) && !m_vertices[v1].m_deleted)
{
std::set<long>::const_iterator ed(m_vertices[v1].m_edges.begin());
std::set<long>::const_iterator itEnd(m_vertices[v1].m_edges.end());
for(; ed != itEnd; ++ed)
{
if ( (m_edges[*ed].m_v1 == v2) ||
(m_edges[*ed].m_v2 == v2) )
{
return m_edges[*ed].m_name;
}
}
}
return -1;
}
void Graph::Print() const
{
std::cout << "-----------------------------" << std::endl;
std::cout << "vertices (" << m_nV << ")" << std::endl;
for (size_t v = 0; v < m_vertices.size(); ++v)
{
const GraphVertex & currentVertex = m_vertices[v];
if (!m_vertices[v].m_deleted)
{
std::cout << currentVertex.m_name << "\t";
std::set<long>::const_iterator ed(currentVertex.m_edges.begin());
std::set<long>::const_iterator itEnd(currentVertex.m_edges.end());
for(; ed != itEnd; ++ed)
{
std::cout << "(" << m_edges[*ed].m_v1 << "," << m_edges[*ed].m_v2 << ") ";
}
std::cout << std::endl;
}
}
std::cout << "vertices (" << m_nE << ")" << std::endl;
for (size_t e = 0; e < m_edges.size(); ++e)
{
const GraphEdge & currentEdge = m_edges[e];
if (!m_edges[e].m_deleted)
{
std::cout << currentEdge.m_name << "\t("
<< m_edges[e].m_v1 << ","
<< m_edges[e].m_v2 << ") "<< std::endl;
}
}
}
void Graph::Clear()
{
m_vertices.clear();
m_edges.clear();
m_nV = 0;
m_nE = 0;
}
long Graph::ExtractCCs()
{
// all CCs to -1
for (size_t v = 0; v < m_vertices.size(); ++v)
{
if (!m_vertices[v].m_deleted)
{
m_vertices[v].m_cc = -1;
}
}
// we get the CCs
m_nCCs = 0;
long v2 = -1;
std::vector<long> temp;
for (size_t v = 0; v < m_vertices.size(); ++v)
{
if (!m_vertices[v].m_deleted && m_vertices[v].m_cc == -1)
{
m_vertices[v].m_cc = static_cast<long>(m_nCCs);
temp.clear();
temp.push_back(m_vertices[v].m_name);
while (temp.size())
{
long vertex = temp[temp.size()-1];
temp.pop_back();
std::set<long>::const_iterator ed(m_vertices[vertex].m_edges.begin());
std::set<long>::const_iterator itEnd(m_vertices[vertex].m_edges.end());
for(; ed != itEnd; ++ed)
{
if (m_edges[*ed].m_v1 == vertex)
{
v2 = m_edges[*ed].m_v2;
}
else
{
v2 = m_edges[*ed].m_v1;
}
if ( !m_vertices[v2].m_deleted && m_vertices[v2].m_cc == -1)
{
m_vertices[v2].m_cc = static_cast<long>(m_nCCs);
temp.push_back(v2);
}
}
}
m_nCCs++;
}
}
return static_cast<long>(m_nCCs);
}
}

120
extern/HACD/hacdGraph.h vendored Normal file
View File

@@ -0,0 +1,120 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef HACD_GRAPH_H
#define HACD_GRAPH_H
#include "hacdVersion.h"
#include "hacdVector.h"
#include "hacdICHull.h"
#include <map>
#include <vector>
#include <set>
namespace HACD
{
class GraphVertex;
class GraphEdge;
class Graph;
class HACD;
class GraphVertex
{
public:
bool AddEdge(long name)
{
m_edges.insert(name);
return true;
}
bool DeleteEdge(long name);
GraphVertex();
~GraphVertex(){ delete m_convexHull;};
private:
long m_name;
long m_cc;
std::set<long> m_edges;
bool m_deleted;
std::vector<long> m_ancestors;
std::map<long, DPoint> m_distPoints;
Real m_error;
double m_surf;
double m_volume;
double m_perimeter;
double m_concavity;
ICHull * m_convexHull;
std::set<unsigned long long> m_boudaryEdges;
friend class GraphEdge;
friend class Graph;
friend class HACD;
};
class GraphEdge
{
public:
GraphEdge();
~GraphEdge(){delete m_convexHull;};
private:
long m_name;
long m_v1;
long m_v2;
std::map<long, DPoint> m_distPoints;
Real m_error;
double m_surf;
double m_volume;
double m_perimeter;
double m_concavity;
ICHull * m_convexHull;
std::set<unsigned long long> m_boudaryEdges;
bool m_deleted;
friend class GraphVertex;
friend class Graph;
friend class HACD;
};
class Graph
{
public:
size_t GetNEdges() const { return m_nE;}
size_t GetNVertices() const { return m_nV;}
bool EdgeCollapse(long v1, long v2);
long AddVertex();
long AddEdge(long v1, long v2);
bool DeleteEdge(long name);
bool DeleteVertex(long name);
long GetEdgeID(long v1, long v2) const;
void Clear();
void Print() const;
long ExtractCCs();
Graph();
virtual ~Graph();
void Allocate(size_t nV, size_t nE);
private:
size_t m_nCCs;
size_t m_nV;
size_t m_nE;
std::vector<GraphEdge> m_edges;
std::vector<GraphVertex> m_vertices;
friend class HACD;
};
}
#endif

847
extern/HACD/hacdHACD.cpp vendored Normal file
View File

@@ -0,0 +1,847 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif //_CRT_SECURE_NO_WARNINGS
#include <sstream>
#include "hacdGraph.h"
#include "hacdHACD.h"
#include "hacdICHull.h"
#include <string.h>
#include <algorithm>
#include <iterator>
#include <limits>
bool gCancelRequest=false;
namespace HACD
{
double HACD::Concavity(ICHull & ch, std::map<long, DPoint> & distPoints)
{
double concavity = 0.0;
double distance = 0.0;
std::map<long, DPoint>::iterator itDP(distPoints.begin());
std::map<long, DPoint>::iterator itDPEnd(distPoints.end());
for(; itDP != itDPEnd; ++itDP)
{
if (!(itDP->second).m_computed)
{
if (itDP->first >= 0)
{
distance = ch.ComputeDistance(itDP->first, m_points[itDP->first], m_normals[itDP->first], (itDP->second).m_computed, true);
}
else
{
distance = ch.ComputeDistance(itDP->first, m_facePoints[-itDP->first-1], m_faceNormals[-itDP->first-1], (itDP->second).m_computed, true);
}
}
else
{
distance = (itDP->second).m_dist;
}
if (concavity < distance)
{
concavity = distance;
}
}
return concavity;
}
void HACD::CreateGraph()
{
// vertex to triangle adjacency information
std::vector< std::set<long> > vertexToTriangles;
vertexToTriangles.resize(m_nPoints);
for(size_t t = 0; t < m_nTriangles; ++t)
{
vertexToTriangles[m_triangles[t].X()].insert(static_cast<long>(t));
vertexToTriangles[m_triangles[t].Y()].insert(static_cast<long>(t));
vertexToTriangles[m_triangles[t].Z()].insert(static_cast<long>(t));
}
m_graph.Clear();
m_graph.Allocate(m_nTriangles, 5 * m_nTriangles);
unsigned long long tr1[3];
unsigned long long tr2[3];
long i1, j1, k1, i2, j2, k2;
long t1, t2;
for (size_t v = 0; v < m_nPoints; v++)
{
std::set<long>::const_iterator it1(vertexToTriangles[v].begin()), itEnd(vertexToTriangles[v].end());
for(; it1 != itEnd; ++it1)
{
t1 = *it1;
i1 = m_triangles[t1].X();
j1 = m_triangles[t1].Y();
k1 = m_triangles[t1].Z();
tr1[0] = GetEdgeIndex(i1, j1);
tr1[1] = GetEdgeIndex(j1, k1);
tr1[2] = GetEdgeIndex(k1, i1);
std::set<long>::const_iterator it2(it1);
for(++it2; it2 != itEnd; ++it2)
{
t2 = *it2;
i2 = m_triangles[t2].X();
j2 = m_triangles[t2].Y();
k2 = m_triangles[t2].Z();
tr2[0] = GetEdgeIndex(i2, j2);
tr2[1] = GetEdgeIndex(j2, k2);
tr2[2] = GetEdgeIndex(k2, i2);
int shared = 0;
for(int i = 0; i < 3; ++i)
{
for(int j = 0; j < 3; ++j)
{
if (tr1[i] == tr2[j])
{
shared++;
}
}
}
if (shared == 1) // two triangles are connected if they share exactly one edge
{
m_graph.AddEdge(t1, t2);
}
}
}
}
if (m_ccConnectDist >= 0.0)
{
m_graph.ExtractCCs();
if (m_graph.m_nCCs > 1)
{
std::vector< std::set<long> > cc2V;
cc2V.resize(m_graph.m_nCCs);
long cc;
for(size_t t = 0; t < m_nTriangles; ++t)
{
cc = m_graph.m_vertices[t].m_cc;
cc2V[cc].insert(m_triangles[t].X());
cc2V[cc].insert(m_triangles[t].Y());
cc2V[cc].insert(m_triangles[t].Z());
}
for(size_t cc1 = 0; cc1 < m_graph.m_nCCs; ++cc1)
{
for(size_t cc2 = cc1+1; cc2 < m_graph.m_nCCs; ++cc2)
{
std::set<long>::const_iterator itV1(cc2V[cc1].begin()), itVEnd1(cc2V[cc1].end());
for(; itV1 != itVEnd1; ++itV1)
{
double distC1C2 = std::numeric_limits<double>::max();
double dist;
t1 = -1;
t2 = -1;
std::set<long>::const_iterator itV2(cc2V[cc2].begin()), itVEnd2(cc2V[cc2].end());
for(; itV2 != itVEnd2; ++itV2)
{
dist = (m_points[*itV1] - m_points[*itV2]).GetNorm();
if (dist < distC1C2)
{
distC1C2 = dist;
t1 = *vertexToTriangles[*itV1].begin();
std::set<long>::const_iterator it2(vertexToTriangles[*itV2].begin()),
it2End(vertexToTriangles[*itV2].end());
t2 = -1;
for(; it2 != it2End; ++it2)
{
if (*it2 != t1)
{
t2 = *it2;
break;
}
}
}
}
if (distC1C2 <= m_ccConnectDist && t1 > 0 && t2 > 0)
{
m_graph.AddEdge(t1, t2);
}
}
}
}
}
}
}
void HACD::InitializeDualGraph()
{
long i, j, k;
Vec3<Real> u, v, w, normal;
delete [] m_normals;
m_normals = new Vec3<Real>[m_nPoints];
if (m_addFacesPoints)
{
delete [] m_facePoints;
delete [] m_faceNormals;
m_facePoints = new Vec3<Real>[m_nTriangles];
m_faceNormals = new Vec3<Real>[m_nTriangles];
}
memset(m_normals, 0, sizeof(Vec3<Real>) * m_nPoints);
for(unsigned long f = 0; f < m_nTriangles; f++)
{
if (m_callBack) (*m_callBack)("+ InitializeDualGraph\n", f, m_nTriangles, 0);
if (gCancelRequest)
return;
i = m_triangles[f].X();
j = m_triangles[f].Y();
k = m_triangles[f].Z();
m_graph.m_vertices[f].m_distPoints[i].m_distOnly = false;
m_graph.m_vertices[f].m_distPoints[j].m_distOnly = false;
m_graph.m_vertices[f].m_distPoints[k].m_distOnly = false;
ICHull * ch = new ICHull;
m_graph.m_vertices[f].m_convexHull = ch;
ch->AddPoint(m_points[i], i);
ch->AddPoint(m_points[j], j);
ch->AddPoint(m_points[k], k);
ch->SetDistPoints(&m_graph.m_vertices[f].m_distPoints);
u = m_points[j] - m_points[i];
v = m_points[k] - m_points[i];
w = m_points[k] - m_points[j];
normal = u ^ v;
m_normals[i] += normal;
m_normals[j] += normal;
m_normals[k] += normal;
m_graph.m_vertices[f].m_surf = normal.GetNorm();
m_graph.m_vertices[f].m_perimeter = u.GetNorm() + v.GetNorm() + w.GetNorm();
normal.Normalize();
m_graph.m_vertices[f].m_boudaryEdges.insert(GetEdgeIndex(i,j));
m_graph.m_vertices[f].m_boudaryEdges.insert(GetEdgeIndex(j,k));
m_graph.m_vertices[f].m_boudaryEdges.insert(GetEdgeIndex(k,i));
if(m_addFacesPoints)
{
m_faceNormals[f] = normal;
m_facePoints[f] = (m_points[i] + m_points[j] + m_points[k]) / 3.0;
m_graph.m_vertices[f].m_distPoints[-static_cast<long>(f)-1].m_distOnly = true;
}
if (m_addExtraDistPoints)
{// we need a kd-tree structure to accelerate this part!
long i1, j1, k1;
Vec3<Real> u1, v1, normal1;
normal = -normal;
double distance = 0.0;
double distMin = 0.0;
size_t faceIndex = m_nTriangles;
Vec3<Real> seedPoint((m_points[i] + m_points[j] + m_points[k]) / 3.0);
long nhit = 0;
for(size_t f1 = 0; f1 < m_nTriangles; f1++)
{
i1 = m_triangles[f1].X();
j1 = m_triangles[f1].Y();
k1 = m_triangles[f1].Z();
u1 = m_points[j1] - m_points[i1];
v1 = m_points[k1] - m_points[i1];
normal1 = (u1 ^ v1);
if (normal * normal1 > 0.0)
{
nhit = IntersectRayTriangle(Vec3<double>(seedPoint.X(), seedPoint.Y(), seedPoint.Z()),
Vec3<double>(normal.X(), normal.Y(), normal.Z()),
Vec3<double>(m_points[i1].X(), m_points[i1].Y(), m_points[i1].Z()),
Vec3<double>(m_points[j1].X(), m_points[j1].Y(), m_points[j1].Z()),
Vec3<double>(m_points[k1].X(), m_points[k1].Y(), m_points[k1].Z()),
distance);
if ((nhit==1) && ((distMin > distance) || (faceIndex == m_nTriangles)))
{
distMin = distance;
faceIndex = f1;
}
}
}
if (faceIndex < m_nTriangles )
{
i1 = m_triangles[faceIndex].X();
j1 = m_triangles[faceIndex].Y();
k1 = m_triangles[faceIndex].Z();
m_graph.m_vertices[f].m_distPoints[i1].m_distOnly = true;
m_graph.m_vertices[f].m_distPoints[j1].m_distOnly = true;
m_graph.m_vertices[f].m_distPoints[k1].m_distOnly = true;
if (m_addFacesPoints)
{
m_graph.m_vertices[f].m_distPoints[-static_cast<long>(faceIndex)-1].m_distOnly = true;
}
}
}
}
for (size_t v = 0; v < m_nPoints; v++)
{
m_normals[v].Normalize();
}
}
void HACD::NormalizeData()
{
if (m_nPoints == 0)
{
return;
}
m_barycenter = m_points[0];
Vec3<Real> min = m_points[0];
Vec3<Real> max = m_points[0];
Real x, y, z;
for (size_t v = 1; v < m_nPoints ; v++)
{
m_barycenter += m_points[v];
x = m_points[v].X();
y = m_points[v].Y();
z = m_points[v].Z();
if ( x < min.X()) min.X() = x;
else if ( x > max.X()) max.X() = x;
if ( y < min.Y()) min.Y() = y;
else if ( y > max.Y()) max.Y() = y;
if ( z < min.Z()) min.Z() = z;
else if ( z > max.Z()) max.Z() = z;
}
m_barycenter /= static_cast<Real>(m_nPoints);
m_diag = (max-min).GetNorm();
const Real invDiag = static_cast<Real>(2.0 * m_scale / m_diag);
if (m_diag != 0.0)
{
for (size_t v = 0; v < m_nPoints ; v++)
{
m_points[v] = (m_points[v] - m_barycenter) * invDiag;
}
}
}
void HACD::DenormalizeData()
{
if (m_nPoints == 0)
{
return;
}
if (m_diag != 0.0)
{
const Real diag = static_cast<Real>(m_diag / (2.0 * m_scale));
for (size_t v = 0; v < m_nPoints ; v++)
{
m_points[v] = m_points[v] * diag + m_barycenter;
}
}
}
HACD::HACD(void)
{
m_convexHulls = 0;
m_triangles = 0;
m_points = 0;
m_normals = 0;
m_nTriangles = 0;
m_nPoints = 0;
m_nClusters = 0;
m_concavity = 0.0;
m_diag = 1.0;
m_barycenter = Vec3<Real>(0.0, 0.0,0.0);
m_alpha = 0.1;
m_beta = 0.1;
m_nVerticesPerCH = 30;
m_callBack = 0;
m_addExtraDistPoints = false;
m_addNeighboursDistPoints = false;
m_scale = 1000.0;
m_partition = 0;
m_nMinClusters = 3;
m_facePoints = 0;
m_faceNormals = 0;
m_ccConnectDist = 30;
}
HACD::~HACD(void)
{
delete [] m_normals;
delete [] m_convexHulls;
delete [] m_partition;
delete [] m_facePoints;
delete [] m_faceNormals;
}
int iteration = 0;
void HACD::ComputeEdgeCost(size_t e)
{
GraphEdge & gE = m_graph.m_edges[e];
long v1 = gE.m_v1;
long v2 = gE.m_v2;
if (m_graph.m_vertices[v2].m_distPoints.size()>m_graph.m_vertices[v1].m_distPoints.size())
{
gE.m_v1 = v2;
gE.m_v2 = v1;
//std::swap<long>(v1, v2);
std::swap(v1, v2);
}
GraphVertex & gV1 = m_graph.m_vertices[v1];
GraphVertex & gV2 = m_graph.m_vertices[v2];
// delete old convex-hull
delete gE.m_convexHull;
// create the edge's convex-hull
ICHull * ch = new ICHull;
gE.m_convexHull = ch;
(*ch) = (*gV1.m_convexHull);
// update distPoints
gE.m_distPoints = gV1.m_distPoints;
std::map<long, DPoint>::iterator itDP(gV2.m_distPoints.begin());
std::map<long, DPoint>::iterator itDPEnd(gV2.m_distPoints.end());
std::map<long, DPoint>::iterator itDP1;
for(; itDP != itDPEnd; ++itDP)
{
itDP1 = gE.m_distPoints.find(itDP->first);
if (itDP1 == gE.m_distPoints.end())
{
gE.m_distPoints[itDP->first].m_distOnly = (itDP->second).m_distOnly;
if ( !(itDP->second).m_distOnly )
{
ch->AddPoint(m_points[itDP->first], itDP->first);
}
}
else
{
if ( (itDP1->second).m_distOnly && !(itDP->second).m_distOnly)
{
gE.m_distPoints[itDP->first].m_distOnly = false;
ch->AddPoint(m_points[itDP->first], itDP->first);
}
}
}
ch->SetDistPoints(&gE.m_distPoints);
// create the convex-hull
while (ch->Process() == ICHullErrorInconsistent) // if we face problems when constructing the visual-hull. really ugly!!!!
{
// if (m_callBack) (*m_callBack)("\t Problem with convex-hull construction [HACD::ComputeEdgeCost]\n", 0.0, 0.0, 0);
ch = new ICHull;
CircularList<TMMVertex> & verticesCH = (gE.m_convexHull)->GetMesh().m_vertices;
size_t nV = verticesCH.GetSize();
long ptIndex = 0;
verticesCH.Next();
for(size_t v = 1; v < nV; ++v)
{
ptIndex = verticesCH.GetHead()->GetData().m_name;
ch->AddPoint(m_points[ptIndex], ptIndex);
verticesCH.Next();
}
delete gE.m_convexHull;
gE.m_convexHull = ch;
}
double volume = 0.0;
double concavity = 0.0;
if (ch->IsFlat())
{
bool insideHull;
std::map<long, DPoint>::iterator itDP(gE.m_distPoints.begin());
std::map<long, DPoint>::iterator itDPEnd(gE.m_distPoints.end());
for(; itDP != itDPEnd; ++itDP)
{
if (itDP->first >= 0)
{
concavity = std::max<double>(concavity, ch->ComputeDistance(itDP->first, m_points[itDP->first], m_normals[itDP->first], insideHull, false));
}
}
}
else
{
if (m_addNeighboursDistPoints)
{ // add distance points from adjacent clusters
std::set<long> eEdges;
std::set_union(gV1.m_edges.begin(),
gV1.m_edges.end(),
gV2.m_edges.begin(),
gV2.m_edges.end(),
std::inserter( eEdges, eEdges.begin() ) );
std::set<long>::const_iterator ed(eEdges.begin());
std::set<long>::const_iterator itEnd(eEdges.end());
long a, b, c;
for(; ed != itEnd; ++ed)
{
a = m_graph.m_edges[*ed].m_v1;
b = m_graph.m_edges[*ed].m_v2;
if ( a != v2 && a != v1)
{
c = a;
}
else if ( b != v2 && b != v1)
{
c = b;
}
else
{
c = -1;
}
if ( c > 0)
{
GraphVertex & gVC = m_graph.m_vertices[c];
std::map<long, DPoint>::iterator itDP(gVC.m_distPoints.begin());
std::map<long, DPoint>::iterator itDPEnd(gVC.m_distPoints.end());
std::map<long, DPoint>::iterator itDP1;
for(; itDP != itDPEnd; ++itDP)
{
itDP1 = gE.m_distPoints.find(itDP->first);
if (itDP1 == gE.m_distPoints.end())
{
if (itDP->first >= 0 && itDP1 == gE.m_distPoints.end() && ch->IsInside(m_points[itDP->first]))
{
gE.m_distPoints[itDP->first].m_distOnly = true;
}
else if (itDP->first < 0 && ch->IsInside(m_facePoints[-itDP->first-1]))
{
gE.m_distPoints[itDP->first].m_distOnly = true;
}
}
}
}
}
}
concavity = Concavity(*ch, gE.m_distPoints);
}
// compute boudary edges
double perimeter = 0.0;
double surf = 1.0;
if (m_alpha > 0.0)
{
gE.m_boudaryEdges.clear();
std::set_symmetric_difference (gV1.m_boudaryEdges.begin(),
gV1.m_boudaryEdges.end(),
gV2.m_boudaryEdges.begin(),
gV2.m_boudaryEdges.end(),
std::inserter( gE.m_boudaryEdges,
gE.m_boudaryEdges.begin() ) );
std::set<unsigned long long>::const_iterator itBE(gE.m_boudaryEdges.begin());
std::set<unsigned long long>::const_iterator itBEEnd(gE.m_boudaryEdges.end());
for(; itBE != itBEEnd; ++itBE)
{
perimeter += (m_points[static_cast<long>((*itBE) >> 32)] -
m_points[static_cast<long>((*itBE) & 0xFFFFFFFFULL)]).GetNorm();
}
surf = gV1.m_surf + gV2.m_surf;
}
double ratio = perimeter * perimeter / (4.0 * sc_pi * surf);
gE.m_volume = (m_beta == 0.0)?0.0:ch->ComputeVolume()/pow(m_scale, 3.0); // cluster's volume
gE.m_surf = surf; // cluster's area
gE.m_perimeter = perimeter; // cluster's perimeter
gE.m_concavity = concavity; // cluster's concavity
gE.m_error = static_cast<Real>(concavity + m_alpha * ratio + m_beta * volume); // cluster's priority
}
bool HACD::InitializePriorityQueue()
{
m_pqueue.reserve(m_graph.m_nE + 100);
for (size_t e=0; e < m_graph.m_nE; ++e)
{
ComputeEdgeCost(static_cast<long>(e));
m_pqueue.push(GraphEdgePriorityQueue(static_cast<long>(e), m_graph.m_edges[e].m_error));
}
return true;
}
void HACD::Simplify()
{
long v1 = -1;
long v2 = -1;
double progressOld = -1.0;
double progress = 0.0;
double globalConcavity = 0.0;
char msg[1024];
double ptgStep = 1.0;
while ( (globalConcavity < m_concavity) &&
(m_graph.GetNVertices() > m_nMinClusters) &&
(m_graph.GetNEdges() > 0))
{
progress = 100.0-m_graph.GetNVertices() * 100.0 / m_nTriangles;
if (fabs(progress-progressOld) > ptgStep && m_callBack)
{
sprintf(msg, "%3.2f %% V = %lu \t C = %f \t \t \r", progress, static_cast<unsigned long>(m_graph.GetNVertices()), globalConcavity);
(*m_callBack)(msg, progress, globalConcavity, m_graph.GetNVertices());
progressOld = progress;
if (progress > 99.0)
{
ptgStep = 0.01;
}
else if (progress > 90.0)
{
ptgStep = 0.1;
}
}
GraphEdgePriorityQueue currentEdge(0,0.0);
bool done = false;
do
{
done = false;
if (m_pqueue.size() == 0)
{
done = true;
break;
}
currentEdge = m_pqueue.top();
m_pqueue.pop();
}
while ( m_graph.m_edges[currentEdge.m_name].m_deleted ||
m_graph.m_edges[currentEdge.m_name].m_error != currentEdge.m_priority);
if (m_graph.m_edges[currentEdge.m_name].m_concavity < m_concavity && !done)
{
globalConcavity = std::max<double>(globalConcavity ,m_graph.m_edges[currentEdge.m_name].m_concavity);
v1 = m_graph.m_edges[currentEdge.m_name].m_v1;
v2 = m_graph.m_edges[currentEdge.m_name].m_v2;
// update vertex info
m_graph.m_vertices[v1].m_error = m_graph.m_edges[currentEdge.m_name].m_error;
m_graph.m_vertices[v1].m_surf = m_graph.m_edges[currentEdge.m_name].m_surf;
m_graph.m_vertices[v1].m_volume = m_graph.m_edges[currentEdge.m_name].m_volume;
m_graph.m_vertices[v1].m_concavity = m_graph.m_edges[currentEdge.m_name].m_concavity;
m_graph.m_vertices[v1].m_perimeter = m_graph.m_edges[currentEdge.m_name].m_perimeter;
m_graph.m_vertices[v1].m_distPoints = m_graph.m_edges[currentEdge.m_name].m_distPoints;
(*m_graph.m_vertices[v1].m_convexHull) = (*m_graph.m_edges[currentEdge.m_name].m_convexHull);
(m_graph.m_vertices[v1].m_convexHull)->SetDistPoints(&(m_graph.m_vertices[v1].m_distPoints));
m_graph.m_vertices[v1].m_boudaryEdges = m_graph.m_edges[currentEdge.m_name].m_boudaryEdges;
// We apply the optimal ecol
// std::cout << "v1 " << v1 << " v2 " << v2 << std::endl;
m_graph.EdgeCollapse(v1, v2);
// recompute the adjacent edges costs
std::set<long>::const_iterator itE(m_graph.m_vertices[v1].m_edges.begin()),
itEEnd(m_graph.m_vertices[v1].m_edges.end());
for(; itE != itEEnd; ++itE)
{
size_t e = *itE;
ComputeEdgeCost(static_cast<long>(e));
m_pqueue.push(GraphEdgePriorityQueue(static_cast<long>(e), m_graph.m_edges[e].m_error));
}
}
else
{
break;
}
}
while (!m_pqueue.empty())
{
m_pqueue.pop();
}
m_cVertices.clear();
m_nClusters = m_graph.GetNVertices();
m_cVertices.reserve(m_nClusters);
for (size_t p=0, v = 0; v != m_graph.m_vertices.size(); ++v)
{
if (!m_graph.m_vertices[v].m_deleted)
{
if (m_callBack)
{
char msg[1024];
sprintf(msg, "\t CH \t %lu \t %lf \t %lf\n", static_cast<unsigned long>(p), m_graph.m_vertices[v].m_concavity, m_graph.m_vertices[v].m_error);
(*m_callBack)(msg, 0.0, 0.0, m_nClusters);
p++;
}
m_cVertices.push_back(static_cast<long>(v));
}
}
if (m_callBack)
{
sprintf(msg, "# clusters = %lu \t C = %f\n", static_cast<unsigned long>(m_nClusters), globalConcavity);
(*m_callBack)(msg, progress, globalConcavity, m_graph.GetNVertices());
}
}
bool HACD::Compute(bool fullCH, bool exportDistPoints)
{
gCancelRequest = false;
if ( !m_points || !m_triangles || !m_nPoints || !m_nTriangles)
{
return false;
}
size_t nV = m_nTriangles;
if (m_callBack)
{
std::ostringstream msg;
msg << "+ Mesh" << std::endl;
msg << "\t # vertices \t" << m_nPoints << std::endl;
msg << "\t # triangles \t" << m_nTriangles << std::endl;
msg << "+ Parameters" << std::endl;
msg << "\t min # of clusters \t" << m_nMinClusters << std::endl;
msg << "\t max concavity \t" << m_concavity << std::endl;
msg << "\t compacity weigth \t" << m_alpha << std::endl;
msg << "\t volume weigth \t" << m_beta << std::endl;
msg << "\t # vertices per convex-hull \t" << m_nVerticesPerCH << std::endl;
msg << "\t scale \t" << m_scale << std::endl;
msg << "\t add extra distance points \t" << m_addExtraDistPoints << std::endl;
msg << "\t add neighbours distance points \t" << m_addNeighboursDistPoints << std::endl;
msg << "\t add face distance points \t" << m_addFacesPoints << std::endl;
msg << "\t produce full convex-hulls \t" << fullCH << std::endl;
msg << "\t max. distance to connect CCs \t" << m_ccConnectDist << std::endl;
(*m_callBack)(msg.str().c_str(), 0.0, 0.0, nV);
}
if (m_callBack) (*m_callBack)("+ Normalizing Data\n", 0.0, 0.0, nV);
NormalizeData();
if (m_callBack) (*m_callBack)("+ Creating Graph\n", 0.0, 0.0, nV);
CreateGraph();
// Compute the surfaces and perimeters of all the faces
if (m_callBack) (*m_callBack)("+ Initializing Dual Graph\n", 0.0, 0.0, nV);
if (gCancelRequest)
return false;
InitializeDualGraph();
if (m_callBack) (*m_callBack)("+ Initializing Priority Queue\n", 0.0, 0.0, nV);
if (gCancelRequest)
return false;
InitializePriorityQueue();
// we simplify the graph
if (m_callBack) (*m_callBack)("+ Simplification ...\n", 0.0, 0.0, m_nTriangles);
Simplify();
if (m_callBack) (*m_callBack)("+ Denormalizing Data\n", 0.0, 0.0, m_nClusters);
DenormalizeData();
if (m_callBack) (*m_callBack)("+ Computing final convex-hulls\n", 0.0, 0.0, m_nClusters);
delete [] m_convexHulls;
m_convexHulls = new ICHull[m_nClusters];
delete [] m_partition;
m_partition = new long [m_nTriangles];
for (size_t p = 0; p != m_cVertices.size(); ++p)
{
size_t v = m_cVertices[p];
m_partition[v] = static_cast<long>(p);
for(size_t a = 0; a < m_graph.m_vertices[v].m_ancestors.size(); a++)
{
m_partition[m_graph.m_vertices[v].m_ancestors[a]] = static_cast<long>(p);
}
// compute the convex-hull
const std::map<long, DPoint> & pointsCH = m_graph.m_vertices[v].m_distPoints;
std::map<long, DPoint>::const_iterator itCH(pointsCH.begin());
std::map<long, DPoint>::const_iterator itCHEnd(pointsCH.end());
for(; itCH != itCHEnd; ++itCH)
{
if (!(itCH->second).m_distOnly)
{
m_convexHulls[p].AddPoint(m_points[itCH->first], itCH->first);
}
}
m_convexHulls[p].SetDistPoints(&m_graph.m_vertices[v].m_distPoints);
if (fullCH)
{
m_convexHulls[p].Process();
}
else
{
m_convexHulls[p].Process(static_cast<unsigned long>(m_nVerticesPerCH));
}
if (exportDistPoints)
{
itCH = pointsCH.begin();
for(; itCH != itCHEnd; ++itCH)
{
if ((itCH->second).m_distOnly)
{
if (itCH->first >= 0)
{
m_convexHulls[p].AddPoint(m_points[itCH->first], itCH->first);
}
else
{
m_convexHulls[p].AddPoint(m_facePoints[-itCH->first-1], itCH->first);
}
}
}
}
}
return true;
}
size_t HACD::GetNTrianglesCH(size_t numCH) const
{
if (numCH >= m_nClusters)
{
return 0;
}
return m_convexHulls[numCH].GetMesh().GetNTriangles();
}
size_t HACD::GetNPointsCH(size_t numCH) const
{
if (numCH >= m_nClusters)
{
return 0;
}
return m_convexHulls[numCH].GetMesh().GetNVertices();
}
bool HACD::GetCH(size_t numCH, Vec3<Real> * const points, Vec3<long> * const triangles)
{
if (numCH >= m_nClusters)
{
return false;
}
m_convexHulls[numCH].GetMesh().GetIFS(points, triangles);
return true;
}
bool HACD::Save(const char * fileName, bool uniColor, long numCluster) const
{
std::ofstream fout(fileName);
if (fout.is_open())
{
if (m_callBack)
{
char msg[1024];
sprintf(msg, "Saving %s\n", fileName);
(*m_callBack)(msg, 0.0, 0.0, m_graph.GetNVertices());
}
Material mat;
if (numCluster < 0)
{
for (size_t p = 0; p != m_nClusters; ++p)
{
if (!uniColor)
{
mat.m_diffuseColor.X() = mat.m_diffuseColor.Y() = mat.m_diffuseColor.Z() = 0.0;
while (mat.m_diffuseColor.X() == mat.m_diffuseColor.Y() ||
mat.m_diffuseColor.Z() == mat.m_diffuseColor.Y() ||
mat.m_diffuseColor.Z() == mat.m_diffuseColor.X() )
{
mat.m_diffuseColor.X() = (rand()%100) / 100.0;
mat.m_diffuseColor.Y() = (rand()%100) / 100.0;
mat.m_diffuseColor.Z() = (rand()%100) / 100.0;
}
}
m_convexHulls[p].GetMesh().SaveVRML2(fout, mat);
}
}
else if (numCluster < static_cast<long>(m_cVertices.size()))
{
m_convexHulls[numCluster].GetMesh().SaveVRML2(fout, mat);
}
fout.close();
return true;
}
else
{
if (m_callBack)
{
char msg[1024];
sprintf(msg, "Error saving %s\n", fileName);
(*m_callBack)(msg, 0.0, 0.0, m_graph.GetNVertices());
}
return false;
}
}
}

282
extern/HACD/hacdHACD.h vendored Normal file
View File

@@ -0,0 +1,282 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef HACD_HACD_H
#define HACD_HACD_H
#include "hacdVersion.h"
#include "hacdVector.h"
#include "hacdGraph.h"
#include "hacdICHull.h"
#include <set>
#include <vector>
#include <queue>
#include <functional>
namespace HACD
{
const double sc_pi = 3.14159265;
class HACD;
// just to be able to set the capcity of the container
template<class _Ty, class _Container = std::vector<_Ty>, class _Pr = std::less<typename _Container::value_type> >
class reservable_priority_queue: public std::priority_queue<_Ty, _Container, _Pr>
{
typedef typename std::priority_queue<_Ty, _Container, _Pr>::size_type size_type;
public:
reservable_priority_queue(size_type capacity = 0) { reserve(capacity); };
void reserve(size_type capacity) { this->c.reserve(capacity); }
size_type capacity() const { return this->c.capacity(); }
};
//! priority queque element
class GraphEdgePriorityQueue
{
public:
//! Constructor
//! @param name edge's id
//! @param priority edge's priority
GraphEdgePriorityQueue(long name, Real priority)
{
m_name = name;
m_priority = priority;
}
//! Destructor
~GraphEdgePriorityQueue(void){}
private:
long m_name; //!< edge name
Real m_priority; //!< priority
//! Operator < for GraphEdgePQ
friend bool operator<(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs);
//! Operator > for GraphEdgePQ
friend bool operator>(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs);
friend class HACD;
};
inline bool operator<(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs)
{
return lhs.m_priority<rhs.m_priority;
}
inline bool operator>(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs)
{
return lhs.m_priority>rhs.m_priority;
}
typedef bool (*CallBackFunction)(const char *, double, double, size_t);
//! Provides an implementation of the Hierarchical Approximate Convex Decomposition (HACD) technique described in "A Simple and Efficient Approach for 3D Mesh Approximate Convex Decomposition" Game Programming Gems 8 - Chapter 2.8, p.202. A short version of the chapter was published in ICIP09 and is available at ftp://ftp.elet.polimi.it/users/Stefano.Tubaro/ICIP_USB_Proceedings_v2/pdfs/0003501.pdf
class HACD
{
public:
//! Gives the triangles partitionas an array of size m_nTriangles where the i-th element specifies the cluster to which belong the i-th triangle
//! @return triangles partition
const long * const GetPartition() const { return m_partition;}
//! Sets the scale factor
//! @param scale scale factor
void SetScaleFactor(double scale) { m_scale = scale;}
//! Gives the scale factor
//! @return scale factor
const double GetScaleFactor() const { return m_scale;}
//! Sets the call-back function
//! @param callBack pointer to the call-back function
void SetCallBack(CallBackFunction callBack) { m_callBack = callBack;}
//! Gives the call-back function
//! @return pointer to the call-back function
const CallBackFunction GetCallBack() const { return m_callBack;}
//! Specifies whether faces points should be added when computing the concavity
//! @param addFacesPoints true = faces points should be added
void SetAddFacesPoints(bool addFacesPoints) { m_addFacesPoints = addFacesPoints;}
//! Specifies wheter faces points should be added when computing the concavity
//! @return true = faces points should be added
const bool GetAddFacesPoints() const { return m_addFacesPoints;}
//! Specifies whether extra points should be added when computing the concavity
//! @param addExteraDistPoints true = extra points should be added
void SetAddExtraDistPoints(bool addExtraDistPoints) { m_addExtraDistPoints = addExtraDistPoints;}
//! Specifies wheter extra points should be added when computing the concavity
//! @return true = extra points should be added
const bool GetAddExtraDistPoints() const { return m_addExtraDistPoints;}
//! Specifies whether extra points should be added when computing the concavity
//! @param addExteraDistPoints true = extra points should be added
void SetAddNeighboursDistPoints(bool addNeighboursDistPoints) { m_addNeighboursDistPoints = addNeighboursDistPoints;}
//! Specifies wheter extra points should be added when computing the concavity
//! @return true = extra points should be added
const bool GetAddNeighboursDistPoints() const { return m_addNeighboursDistPoints;}
//! Sets the points of the input mesh (Remark: the input points will be scaled and shifted. Use DenormalizeData() to invert those operations)
//! @param points pointer to the input points
void SetPoints(Vec3<Real> * points) { m_points = points;}
//! Gives the points of the input mesh (Remark: the input points will be scaled and shifted. Use DenormalizeData() to invert those operations)
//! @return pointer to the input points
const Vec3<Real> * GetPoints() const { return m_points;}
//! Sets the triangles of the input mesh.
//! @param triangles points pointer to the input points
void SetTriangles(Vec3<long> * triangles) { m_triangles = triangles;}
//! Gives the triangles in the input mesh
//! @return pointer to the input triangles
const Vec3<long> * GetTriangles() const { return m_triangles;}
//! Sets the number of points in the input mesh.
//! @param nPoints number of points the input mesh
void SetNPoints(size_t nPoints) { m_nPoints = nPoints;}
//! Gives the number of points in the input mesh.
//! @return number of points the input mesh
const size_t GetNPoints() const { return m_nPoints;}
//! Sets the number of triangles in the input mesh.
//! @param nTriangles number of triangles in the input mesh
void SetNTriangles(size_t nTriangles) { m_nTriangles = nTriangles;}
//! Gives the number of triangles in the input mesh.
//! @return number of triangles the input mesh
const size_t GetNTriangles() const { return m_nTriangles;}
//! Sets the minimum number of clusters to be generated.
//! @param nClusters minimum number of clusters
void SetNClusters(size_t nClusters) { m_nMinClusters = nClusters;}
//! Gives the number of generated clusters.
//! @return number of generated clusters
const size_t GetNClusters() const { return m_nClusters;}
//! Sets the maximum allowed concavity.
//! @param concavity maximum concavity
void SetConcavity(double concavity) { m_concavity = concavity;}
//! Gives the maximum allowed concavity.
//! @return maximum concavity
double GetConcavity() const { return m_concavity;}
//! Sets the maximum allowed distance to get CCs connected.
//! @param concavity maximum distance to get CCs connected
void SetConnectDist(double ccConnectDist) { m_ccConnectDist = ccConnectDist;}
//! Gives the maximum allowed distance to get CCs connected.
//! @return maximum distance to get CCs connected
double GetConnectDist() const { return m_ccConnectDist;}
//! Sets the volume weight.
//! @param beta volume weight
void SetVolumeWeight(double beta) { m_beta = beta;}
//! Gives the volume weight.
//! @return volume weight
double GetVolumeWeight() const { return m_beta;}
//! Sets the compacity weight (i.e. parameter alpha in ftp://ftp.elet.polimi.it/users/Stefano.Tubaro/ICIP_USB_Proceedings_v2/pdfs/0003501.pdf).
//! @param alpha compacity weight
void SetCompacityWeight(double alpha) { m_alpha = alpha;}
//! Gives the compacity weight (i.e. parameter alpha in ftp://ftp.elet.polimi.it/users/Stefano.Tubaro/ICIP_USB_Proceedings_v2/pdfs/0003501.pdf).
//! @return compacity weight
double GetCompacityWeight() const { return m_alpha;}
//! Sets the maximum number of vertices for each generated convex-hull.
//! @param nVerticesPerCH maximum # vertices per CH
void SetNVerticesPerCH(size_t nVerticesPerCH) { m_nVerticesPerCH = nVerticesPerCH;}
//! Gives the maximum number of vertices for each generated convex-hull.
//! @return maximum # vertices per CH
const size_t GetNVerticesPerCH() const { return m_nVerticesPerCH;}
//! Gives the number of vertices for the cluster number numCH.
//! @return number of vertices
size_t GetNPointsCH(size_t numCH) const;
//! Gives the number of triangles for the cluster number numCH.
//! @param numCH cluster's number
//! @return number of triangles
size_t GetNTrianglesCH(size_t numCH) const;
//! Gives the vertices and the triangles of the cluster number numCH.
//! @param numCH cluster's number
//! @param points pointer to the vector of points to be filled
//! @param triangles pointer to the vector of triangles to be filled
//! @return true if sucess
bool GetCH(size_t numCH, Vec3<Real> * const points, Vec3<long> * const triangles);
//! Computes the HACD decomposition.
//! @param fullCH specifies whether to generate convex-hulls with a full or limited (i.e. < m_nVerticesPerCH) number of vertices
//! @param exportDistPoints specifies wheter distance points should ne exported or not (used only for debugging).
//! @return true if sucess
bool Compute(bool fullCH=false, bool exportDistPoints=false);
//! Saves the generated convex-hulls in a VRML 2.0 file.
//! @param fileName the output file name
//! @param uniColor specifies whether the different convex-hulls should have the same color or not
//! @param numCluster specifies the cluster to be saved, if numCluster < 0 export all clusters
//! @return true if sucess
bool Save(const char * fileName, bool uniColor, long numCluster=-1) const;
//! Shifts and scales to the data to have all the coordinates between 0.0 and 1000.0.
void NormalizeData();
//! Inverse the operations applied by NormalizeData().
void DenormalizeData();
//! Constructor.
HACD(void);
//! Destructor.
~HACD(void);
private:
//! Gives the edge index.
//! @param a first vertex id
//! @param b second vertex id
//! @return edge's index
static unsigned long long GetEdgeIndex(unsigned long long a, unsigned long long b)
{
if (a > b) return (a << 32) + b;
else return (b << 32) + a;
}
//! Computes the concavity of a cluster.
//! @param ch the cluster's convex-hull
//! @param distPoints the cluster's points
//! @return cluster's concavity
double Concavity(ICHull & ch, std::map<long, DPoint> & distPoints);
//! Computes the perimeter of a cluster.
//! @param triIndices the cluster's triangles
//! @param distPoints the cluster's points
//! @return cluster's perimeter
double ComputePerimeter(const std::vector<long> & triIndices) const;
//! Creates the Graph by associating to each mesh triangle a vertex in the graph and to each couple of adjacent triangles an edge in the graph.
void CreateGraph();
//! Initializes the graph costs and computes the vertices normals
void InitializeDualGraph();
//! Computes the cost of an edge
//! @param e edge's id
void ComputeEdgeCost(size_t e);
//! Initializes the priority queue
//! @param fast specifies whether fast mode is used
//! @return true if success
bool InitializePriorityQueue();
//! Cleans the intersection between convex-hulls
void CleanClusters();
//! Computes convex-hulls from partition information
//! @param fullCH specifies whether to generate convex-hulls with a full or limited (i.e. < m_nVerticesPerCH) number of vertices
void ComputeConvexHulls(bool fullCH);
//! Simplifies the graph
//! @param fast specifies whether fast mode is used
void Simplify();
private:
double m_scale; //>! scale factor used for NormalizeData() and DenormalizeData()
Vec3<long> * m_triangles; //>! pointer the triangles array
Vec3<Real> * m_points; //>! pointer the points array
Vec3<Real> * m_facePoints; //>! pointer to the faces points array
Vec3<Real> * m_faceNormals; //>! pointer to the faces normals array
Vec3<Real> * m_normals; //>! pointer the normals array
size_t m_nTriangles; //>! number of triangles in the original mesh
size_t m_nPoints; //>! number of vertices in the original mesh
size_t m_nClusters; //>! number of clusters
size_t m_nMinClusters; //>! minimum number of clusters
double m_ccConnectDist; //>! maximum allowed distance to connect CCs
double m_concavity; //>! maximum concavity
double m_alpha; //>! compacity weigth
double m_beta; //>! volume weigth
double m_diag; //>! length of the BB diagonal
Vec3<Real> m_barycenter; //>! barycenter of the mesh
std::vector< long > m_cVertices; //>! array of vertices each belonging to a different cluster
ICHull * m_convexHulls; //>! convex-hulls associated with the final HACD clusters
Graph m_graph; //>! simplification graph
size_t m_nVerticesPerCH; //>! maximum number of vertices per convex-hull
reservable_priority_queue<GraphEdgePriorityQueue,
std::vector<GraphEdgePriorityQueue>,
std::greater<std::vector<GraphEdgePriorityQueue>::value_type> > m_pqueue; //!> priority queue
HACD(const HACD & rhs);
CallBackFunction m_callBack; //>! call-back function
long * m_partition; //>! array of size m_nTriangles where the i-th element specifies the cluster to which belong the i-th triangle
bool m_addFacesPoints; //>! specifies whether to add faces points or not
bool m_addExtraDistPoints; //>! specifies whether to add extra points for concave shapes or not
bool m_addNeighboursDistPoints; //>! specifies whether to add extra points from adjacent clusters or not
};
}
#endif

1010
extern/HACD/hacdICHull.cpp vendored Normal file

File diff suppressed because it is too large Load Diff

120
extern/HACD/hacdICHull.h vendored Normal file
View File

@@ -0,0 +1,120 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef HACD_ICHULL_H
#define HACD_ICHULL_H
#include "hacdVersion.h"
#include "hacdManifoldMesh.h"
#include "hacdVector.h"
#include <vector>
#include <map>
namespace HACD
{
class DPoint;
class HACD;
//! Incremental Convex Hull algorithm (cf. http://maven.smith.edu/~orourke/books/ftp.html ).
enum ICHullError
{
ICHullErrorOK = 0,
ICHullErrorCoplanarPoints,
ICHullErrorNoVolume,
ICHullErrorInconsistent,
ICHullErrorNotEnoughPoints
};
class ICHull
{
public:
//!
bool IsFlat() { return m_isFlat;}
//!
std::map<long, DPoint> * GetDistPoints() const { return m_distPoints;}
//!
void SetDistPoints(std::map<long, DPoint> * distPoints) { m_distPoints = distPoints;}
//! Returns the computed mesh
TMMesh & GetMesh() { return m_mesh;}
//! Add one point to the convex-hull
bool AddPoint(const Vec3<Real> & point) {return AddPoints(&point, 1);}
//! Add one point to the convex-hull
bool AddPoint(const Vec3<Real> & point, long id);
//! Add points to the convex-hull
bool AddPoints(const Vec3<Real> * points, size_t nPoints);
bool AddPoints(std::vector< Vec3<Real> > points);
//!
ICHullError Process();
//!
ICHullError Process(unsigned long nPointsCH);
//!
double ComputeVolume();
//!
bool IsInside(const Vec3<Real> & pt0);
//!
double ComputeDistance(long name, const Vec3<Real> & pt, const Vec3<Real> & normal, bool & insideHull, bool updateIncidentPoints);
//!
const ICHull & operator=(ICHull & rhs);
//! Constructor
ICHull(void);
//! Destructor
virtual ~ICHull(void) {};
private:
//! DoubleTriangle builds the initial double triangle. It first finds 3 noncollinear points and makes two faces out of them, in opposite order. It then finds a fourth point that is not coplanar with that face. The vertices are stored in the face structure in counterclockwise order so that the volume between the face and the point is negative. Lastly, the 3 newfaces to the fourth point are constructed and the data structures are cleaned up.
ICHullError DoubleTriangle();
//! MakeFace creates a new face structure from three vertices (in ccw order). It returns a pointer to the face.
CircularListElement<TMMTriangle> * MakeFace(CircularListElement<TMMVertex> * v0,
CircularListElement<TMMVertex> * v1,
CircularListElement<TMMVertex> * v2,
CircularListElement<TMMTriangle> * fold);
//!
CircularListElement<TMMTriangle> * MakeConeFace(CircularListElement<TMMEdge> * e, CircularListElement<TMMVertex> * v);
//!
bool ProcessPoint();
//!
bool ComputePointVolume(double &totalVolume, bool markVisibleFaces);
//!
bool FindMaxVolumePoint();
//!
bool CleanEdges();
//!
bool CleanVertices(unsigned long & addedPoints);
//!
bool CleanTriangles();
//!
bool CleanUp(unsigned long & addedPoints);
//!
bool MakeCCW(CircularListElement<TMMTriangle> * f,
CircularListElement<TMMEdge> * e,
CircularListElement<TMMVertex> * v);
void Clear();
private:
static const long sc_dummyIndex;
static const double sc_distMin;
TMMesh m_mesh;
std::vector<CircularListElement<TMMEdge> *> m_edgesToDelete;
std::vector<CircularListElement<TMMEdge> *> m_edgesToUpdate;
std::vector<CircularListElement<TMMTriangle> *> m_trianglesToDelete;
std::map<long, DPoint> * m_distPoints;
CircularListElement<TMMVertex> * m_dummyVertex;
Vec3<Real> m_normal;
bool m_isFlat;
ICHull(const ICHull & rhs);
friend class HACD;
};
}
#endif

577
extern/HACD/hacdManifoldMesh.cpp vendored Normal file
View File

@@ -0,0 +1,577 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "hacdManifoldMesh.h"
using namespace std;
namespace HACD
{
Material::Material(void)
{
m_diffuseColor.X() = 0.5;
m_diffuseColor.Y() = 0.5;
m_diffuseColor.Z() = 0.5;
m_specularColor.X() = 0.5;
m_specularColor.Y() = 0.5;
m_specularColor.Z() = 0.5;
m_ambientIntensity = 0.4;
m_emissiveColor.X() = 0.0;
m_emissiveColor.Y() = 0.0;
m_emissiveColor.Z() = 0.0;
m_shininess = 0.4;
m_transparency = 0.0;
}
TMMVertex::TMMVertex(void)
{
m_name = 0;
m_id = 0;
m_duplicate = 0;
m_onHull = false;
m_tag = false;
}
TMMVertex::~TMMVertex(void)
{
}
TMMEdge::TMMEdge(void)
{
m_id = 0;
m_triangles[0] = m_triangles[1] = m_newFace = 0;
m_vertices[0] = m_vertices[1] = 0;
}
TMMEdge::~TMMEdge(void)
{
}
TMMTriangle::TMMTriangle(void)
{
m_id = 0;
for(int i = 0; i < 3; i++)
{
m_edges[i] = 0;
m_vertices[0] = 0;
}
m_visible = false;
}
TMMTriangle::~TMMTriangle(void)
{
}
TMMesh::TMMesh(void)
{
m_barycenter = Vec3<Real>(0,0,0);
m_diag = 1;
}
TMMesh::~TMMesh(void)
{
}
void TMMesh::Print()
{
size_t nV = m_vertices.GetSize();
std::cout << "-----------------------------" << std::endl;
std::cout << "vertices (" << nV << ")" << std::endl;
for(size_t v = 0; v < nV; v++)
{
const TMMVertex & currentVertex = m_vertices.GetData();
std::cout << currentVertex.m_id << ", "
<< currentVertex.m_pos.X() << ", "
<< currentVertex.m_pos.Y() << ", "
<< currentVertex.m_pos.Z() << std::endl;
m_vertices.Next();
}
size_t nE = m_edges.GetSize();
std::cout << "edges (" << nE << ")" << std::endl;
for(size_t e = 0; e < nE; e++)
{
const TMMEdge & currentEdge = m_edges.GetData();
const CircularListElement<TMMVertex> * v0 = currentEdge.m_vertices[0];
const CircularListElement<TMMVertex> * v1 = currentEdge.m_vertices[1];
const CircularListElement<TMMTriangle> * f0 = currentEdge.m_triangles[0];
const CircularListElement<TMMTriangle> * f1 = currentEdge.m_triangles[1];
std::cout << "-> (" << v0->GetData().m_name << ", " << v1->GetData().m_name << ")" << std::endl;
std::cout << "-> F0 (" << f0->GetData().m_vertices[0]->GetData().m_name << ", "
<< f0->GetData().m_vertices[1]->GetData().m_name << ", "
<< f0->GetData().m_vertices[2]->GetData().m_name <<")" << std::endl;
std::cout << "-> F1 (" << f1->GetData().m_vertices[0]->GetData().m_name << ", "
<< f1->GetData().m_vertices[1]->GetData().m_name << ", "
<< f1->GetData().m_vertices[2]->GetData().m_name << ")" << std::endl;
m_edges.Next();
}
size_t nT = m_triangles.GetSize();
std::cout << "triangles (" << nT << ")" << std::endl;
for(size_t t = 0; t < nT; t++)
{
const TMMTriangle & currentTriangle = m_triangles.GetData();
const CircularListElement<TMMVertex> * v0 = currentTriangle.m_vertices[0];
const CircularListElement<TMMVertex> * v1 = currentTriangle.m_vertices[1];
const CircularListElement<TMMVertex> * v2 = currentTriangle.m_vertices[2];
const CircularListElement<TMMEdge> * e0 = currentTriangle.m_edges[0];
const CircularListElement<TMMEdge> * e1 = currentTriangle.m_edges[1];
const CircularListElement<TMMEdge> * e2 = currentTriangle.m_edges[2];
std::cout << "-> (" << v0->GetData().m_name << ", " << v1->GetData().m_name << ", "<< v2->GetData().m_name << ")" << std::endl;
std::cout << "-> E0 (" << e0->GetData().m_vertices[0]->GetData().m_name << ", "
<< e0->GetData().m_vertices[1]->GetData().m_name << ")" << std::endl;
std::cout << "-> E1 (" << e1->GetData().m_vertices[0]->GetData().m_name << ", "
<< e1->GetData().m_vertices[1]->GetData().m_name << ")" << std::endl;
std::cout << "-> E2 (" << e2->GetData().m_vertices[0]->GetData().m_name << ", "
<< e2->GetData().m_vertices[1]->GetData().m_name << ")" << std::endl;
m_triangles.Next();
}
}
bool TMMesh::Save(const char *fileName)
{
std::ofstream fout(fileName);
std::cout << "Saving " << fileName << std::endl;
if (SaveVRML2(fout))
{
fout.close();
return true;
}
return false;
}
bool TMMesh::SaveVRML2(std::ofstream &fout)
{
return SaveVRML2(fout, Material());
}
bool TMMesh::SaveVRML2(std::ofstream &fout, const Material & material)
{
if (fout.is_open())
{
size_t nV = m_vertices.GetSize();
size_t nT = m_triangles.GetSize();
fout <<"#VRML V2.0 utf8" << std::endl;
fout <<"" << std::endl;
fout <<"# Vertices: " << nV << std::endl;
fout <<"# Triangles: " << nT << std::endl;
fout <<"" << std::endl;
fout <<"Group {" << std::endl;
fout <<" children [" << std::endl;
fout <<" Shape {" << std::endl;
fout <<" appearance Appearance {" << std::endl;
fout <<" material Material {" << std::endl;
fout <<" diffuseColor " << material.m_diffuseColor.X() << " "
<< material.m_diffuseColor.Y() << " "
<< material.m_diffuseColor.Z() << std::endl;
fout <<" ambientIntensity " << material.m_ambientIntensity << std::endl;
fout <<" specularColor " << material.m_specularColor.X() << " "
<< material.m_specularColor.Y() << " "
<< material.m_specularColor.Z() << std::endl;
fout <<" emissiveColor " << material.m_emissiveColor.X() << " "
<< material.m_emissiveColor.Y() << " "
<< material.m_emissiveColor.Z() << std::endl;
fout <<" shininess " << material.m_shininess << std::endl;
fout <<" transparency " << material.m_transparency << std::endl;
fout <<" }" << std::endl;
fout <<" }" << std::endl;
fout <<" geometry IndexedFaceSet {" << std::endl;
fout <<" ccw TRUE" << std::endl;
fout <<" solid TRUE" << std::endl;
fout <<" convex TRUE" << std::endl;
if (GetNVertices() > 0) {
fout <<" coord DEF co Coordinate {" << std::endl;
fout <<" point [" << std::endl;
for(size_t v = 0; v < nV; v++)
{
TMMVertex & currentVertex = m_vertices.GetData();
fout <<" " << currentVertex.m_pos.X() << " "
<< currentVertex.m_pos.Y() << " "
<< currentVertex.m_pos.Z() << "," << std::endl;
currentVertex.m_id = v;
m_vertices.Next();
}
fout <<" ]" << std::endl;
fout <<" }" << std::endl;
}
if (GetNTriangles() > 0) {
fout <<" coordIndex [ " << std::endl;
for(size_t f = 0; f < nT; f++)
{
TMMTriangle & currentTriangle = m_triangles.GetData();
fout <<" " << currentTriangle.m_vertices[0]->GetData().m_id << ", "
<< currentTriangle.m_vertices[1]->GetData().m_id << ", "
<< currentTriangle.m_vertices[2]->GetData().m_id << ", -1," << std::endl;
m_triangles.Next();
}
fout <<" ]" << std::endl;
}
fout <<" }" << std::endl;
fout <<" }" << std::endl;
fout <<" ]" << std::endl;
fout <<"}" << std::endl;
}
return true;
}
void TMMesh::GetIFS(Vec3<Real> * const points, Vec3<long> * const triangles)
{
size_t nV = m_vertices.GetSize();
size_t nT = m_triangles.GetSize();
for(size_t v = 0; v < nV; v++)
{
points[v] = m_vertices.GetData().m_pos;
m_vertices.GetData().m_id = v;
m_vertices.Next();
}
for(size_t f = 0; f < nT; f++)
{
TMMTriangle & currentTriangle = m_triangles.GetData();
triangles[f].X() = static_cast<long>(currentTriangle.m_vertices[0]->GetData().m_id);
triangles[f].Y() = static_cast<long>(currentTriangle.m_vertices[1]->GetData().m_id);
triangles[f].Z() = static_cast<long>(currentTriangle.m_vertices[2]->GetData().m_id);
m_triangles.Next();
}
}
void TMMesh::Clear()
{
m_vertices.Clear();
m_edges.Clear();
m_triangles.Clear();
}
void TMMesh::Copy(TMMesh & mesh)
{
Clear();
// updating the id's
size_t nV = mesh.m_vertices.GetSize();
size_t nE = mesh. m_edges.GetSize();
size_t nT = mesh.m_triangles.GetSize();
for(size_t v = 0; v < nV; v++)
{
mesh.m_vertices.GetData().m_id = v;
mesh.m_vertices.Next();
}
for(size_t e = 0; e < nE; e++)
{
mesh.m_edges.GetData().m_id = e;
mesh.m_edges.Next();
}
for(size_t f = 0; f < nT; f++)
{
mesh.m_triangles.GetData().m_id = f;
mesh.m_triangles.Next();
}
// copying data
m_vertices = mesh.m_vertices;
m_edges = mesh.m_edges;
m_triangles = mesh.m_triangles;
// generating mapping
CircularListElement<TMMVertex> ** vertexMap = new CircularListElement<TMMVertex> * [nV];
CircularListElement<TMMEdge> ** edgeMap = new CircularListElement<TMMEdge> * [nE];
CircularListElement<TMMTriangle> ** triangleMap = new CircularListElement<TMMTriangle> * [nT];
for(size_t v = 0; v < nV; v++)
{
vertexMap[v] = m_vertices.GetHead();
m_vertices.Next();
}
for(size_t e = 0; e < nE; e++)
{
edgeMap[e] = m_edges.GetHead();
m_edges.Next();
}
for(size_t f = 0; f < nT; f++)
{
triangleMap[f] = m_triangles.GetHead();
m_triangles.Next();
}
// updating pointers
for(size_t v = 0; v < nV; v++)
{
if (vertexMap[v]->GetData().m_duplicate)
{
vertexMap[v]->GetData().m_duplicate = edgeMap[vertexMap[v]->GetData().m_duplicate->GetData().m_id];
}
}
for(size_t e = 0; e < nE; e++)
{
if (edgeMap[e]->GetData().m_newFace)
{
edgeMap[e]->GetData().m_newFace = triangleMap[edgeMap[e]->GetData().m_newFace->GetData().m_id];
}
if (nT > 0)
{
for(int f = 0; f < 2; f++)
{
if (edgeMap[e]->GetData().m_triangles[f])
{
edgeMap[e]->GetData().m_triangles[f] = triangleMap[edgeMap[e]->GetData().m_triangles[f]->GetData().m_id];
}
}
}
for(int v = 0; v < 2; v++)
{
if (edgeMap[e]->GetData().m_vertices[v])
{
edgeMap[e]->GetData().m_vertices[v] = vertexMap[edgeMap[e]->GetData().m_vertices[v]->GetData().m_id];
}
}
}
for(size_t f = 0; f < nT; f++)
{
if (nE > 0)
{
for(int e = 0; e < 3; e++)
{
if (triangleMap[f]->GetData().m_edges[e])
{
triangleMap[f]->GetData().m_edges[e] = edgeMap[triangleMap[f]->GetData().m_edges[e]->GetData().m_id];
}
}
}
for(int v = 0; v < 3; v++)
{
if (triangleMap[f]->GetData().m_vertices[v])
{
triangleMap[f]->GetData().m_vertices[v] = vertexMap[triangleMap[f]->GetData().m_vertices[v]->GetData().m_id];
}
}
}
delete [] vertexMap;
delete [] edgeMap;
delete [] triangleMap;
}
long IntersectRayTriangle(const Vec3<double> & P0, const Vec3<double> & dir,
const Vec3<double> & V0, const Vec3<double> & V1,
const Vec3<double> & V2, double &t)
{
Vec3<double> edge1, edge2, edge3;
double det, invDet;
edge1 = V1 - V2;
edge2 = V2 - V0;
Vec3<double> pvec = dir ^ edge2;
det = edge1 * pvec;
if (det == 0.0)
return 0;
invDet = 1.0/det;
Vec3<double> tvec = P0 - V0;
Vec3<double> qvec = tvec ^ edge1;
t = (edge2 * qvec) * invDet;
if (t < 0.0)
{
return 0;
}
edge3 = V0 - V1;
Vec3<double> I(P0 + t * dir);
Vec3<double> s0 = (I-V0) ^ edge3;
Vec3<double> s1 = (I-V1) ^ edge1;
Vec3<double> s2 = (I-V2) ^ edge2;
if (s0*s1 > -1e-9 && s2*s1 > -1e-9)
{
return 1;
}
return 0;
}
bool IntersectLineLine(const Vec3<double> & p1, const Vec3<double> & p2,
const Vec3<double> & p3, const Vec3<double> & p4,
Vec3<double> & pa, Vec3<double> & pb,
double & mua, double & mub)
{
Vec3<double> p13,p43,p21;
double d1343,d4321,d1321,d4343,d2121;
double numer,denom;
p13.X() = p1.X() - p3.X();
p13.Y() = p1.Y() - p3.Y();
p13.Z() = p1.Z() - p3.Z();
p43.X() = p4.X() - p3.X();
p43.Y() = p4.Y() - p3.Y();
p43.Z() = p4.Z() - p3.Z();
if (p43.X()==0.0 && p43.Y()==0.0 && p43.Z()==0.0)
return false;
p21.X() = p2.X() - p1.X();
p21.Y() = p2.Y() - p1.Y();
p21.Z() = p2.Z() - p1.Z();
if (p21.X()==0.0 && p21.Y()==0.0 && p21.Z()==0.0)
return false;
d1343 = p13.X() * p43.X() + p13.Y() * p43.Y() + p13.Z() * p43.Z();
d4321 = p43.X() * p21.X() + p43.Y() * p21.Y() + p43.Z() * p21.Z();
d1321 = p13.X() * p21.X() + p13.Y() * p21.Y() + p13.Z() * p21.Z();
d4343 = p43.X() * p43.X() + p43.Y() * p43.Y() + p43.Z() * p43.Z();
d2121 = p21.X() * p21.X() + p21.Y() * p21.Y() + p21.Z() * p21.Z();
denom = d2121 * d4343 - d4321 * d4321;
if (denom==0.0)
return false;
numer = d1343 * d4321 - d1321 * d4343;
mua = numer / denom;
mub = (d1343 + d4321 * (mua)) / d4343;
pa.X() = p1.X() + mua * p21.X();
pa.Y() = p1.Y() + mua * p21.Y();
pa.Z() = p1.Z() + mua * p21.Z();
pb.X() = p3.X() + mub * p43.X();
pb.Y() = p3.Y() + mub * p43.Y();
pb.Z() = p3.Z() + mub * p43.Z();
return true;
}
long IntersectRayTriangle2(const Vec3<double> & P0, const Vec3<double> & dir,
const Vec3<double> & V0, const Vec3<double> & V1,
const Vec3<double> & V2, double &r)
{
Vec3<double> u, v, n; // triangle vectors
Vec3<double> w0, w; // ray vectors
double a, b; // params to calc ray-plane intersect
// get triangle edge vectors and plane normal
u = V1 - V0;
v = V2 - V0;
n = u ^ v; // cross product
if (n.GetNorm() == 0.0) // triangle is degenerate
return -1; // do not deal with this case
w0 = P0 - V0;
a = - n * w0;
b = n * dir;
if (fabs(b) <= 0.0) { // ray is parallel to triangle plane
if (a == 0.0) // ray lies in triangle plane
return 2;
else return 0; // ray disjoint from plane
}
// get intersect point of ray with triangle plane
r = a / b;
if (r < 0.0) // ray goes away from triangle
return 0; // => no intersect
// for a segment, also test if (r > 1.0) => no intersect
Vec3<double> I = P0 + r * dir; // intersect point of ray and plane
// is I inside T?
double uu, uv, vv, wu, wv, D;
uu = u * u;
uv = u * v;
vv = v * v;
w = I - V0;
wu = w * u;
wv = w * v;
D = uv * uv - uu * vv;
// get and test parametric coords
double s, t;
s = (uv * wv - vv * wu) / D;
if (s < 0.0 || s > 1.0) // I is outside T
return 0;
t = (uv * wu - uu * wv) / D;
if (t < 0.0 || (s + t) > 1.0) // I is outside T
return 0;
return 1; // I is in T
}
bool TMMesh::CheckConsistancy()
{
size_t nE = m_edges.GetSize();
size_t nT = m_triangles.GetSize();
for(size_t e = 0; e < nE; e++)
{
for(int f = 0; f < 2; f++)
{
if (!m_edges.GetHead()->GetData().m_triangles[f])
{
return false;
}
}
m_edges.Next();
}
for(size_t f = 0; f < nT; f++)
{
for(int e = 0; e < 3; e++)
{
int found = 0;
for(int k = 0; k < 2; k++)
{
if (m_triangles.GetHead()->GetData().m_edges[e]->GetData().m_triangles[k] == m_triangles.GetHead())
{
found++;
}
}
if (found != 1)
{
return false;
}
}
m_triangles.Next();
}
return true;
}
bool TMMesh::Normalize()
{
size_t nV = m_vertices.GetSize();
if (nV == 0)
{
return false;
}
m_barycenter = m_vertices.GetHead()->GetData().m_pos;
Vec3<Real> min = m_barycenter;
Vec3<Real> max = m_barycenter;
Real x, y, z;
for(size_t v = 1; v < nV; v++)
{
m_barycenter += m_vertices.GetHead()->GetData().m_pos;
x = m_vertices.GetHead()->GetData().m_pos.X();
y = m_vertices.GetHead()->GetData().m_pos.Y();
z = m_vertices.GetHead()->GetData().m_pos.Z();
if ( x < min.X()) min.X() = x;
else if ( x > max.X()) max.X() = x;
if ( y < min.Y()) min.Y() = y;
else if ( y > max.Y()) max.Y() = y;
if ( z < min.Z()) min.Z() = z;
else if ( z > max.Z()) max.Z() = z;
m_vertices.Next();
}
m_barycenter /= static_cast<Real>(nV);
m_diag = static_cast<Real>(0.001 * (max-min).GetNorm());
const Real invDiag = static_cast<Real>(1.0 / m_diag);
if (m_diag != 0.0)
{
for(size_t v = 0; v < nV; v++)
{
m_vertices.GetHead()->GetData().m_pos = (m_vertices.GetHead()->GetData().m_pos - m_barycenter) * invDiag;
m_vertices.Next();
}
}
return true;
}
bool TMMesh::Denormalize()
{
size_t nV = m_vertices.GetSize();
if (nV == 0)
{
return false;
}
if (m_diag != 0.0)
{
for(size_t v = 0; v < nV; v++)
{
m_vertices.GetHead()->GetData().m_pos = m_vertices.GetHead()->GetData().m_pos * m_diag + m_barycenter;
m_vertices.Next();
}
}
return false;
}
}

250
extern/HACD/hacdManifoldMesh.h vendored Normal file
View File

@@ -0,0 +1,250 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef HACD_MANIFOLD_MESH_H
#define HACD_MANIFOLD_MESH_H
#include <iostream>
#include <fstream>
#include "hacdVersion.h"
#include "hacdCircularList.h"
#include "hacdVector.h"
#include <set>
namespace HACD
{
class TMMTriangle;
class TMMEdge;
class TMMesh;
class ICHull;
class HACD;
class DPoint
{
public:
DPoint(Real dist=0, bool computed=false, bool distOnly=false)
:m_dist(dist),
m_computed(computed),
m_distOnly(distOnly){};
~DPoint(){};
private:
Real m_dist;
bool m_computed;
bool m_distOnly;
friend class TMMTriangle;
friend class TMMesh;
friend class GraphVertex;
friend class GraphEdge;
friend class Graph;
friend class ICHull;
friend class HACD;
};
//! Vertex data structure used in a triangular manifold mesh (TMM).
class TMMVertex
{
public:
TMMVertex(void);
~TMMVertex(void);
private:
Vec3<Real> m_pos;
long m_name;
size_t m_id;
CircularListElement<TMMEdge> * m_duplicate; // pointer to incident cone edge (or NULL)
bool m_onHull;
bool m_tag;
TMMVertex(const TMMVertex & rhs);
friend class HACD;
friend class ICHull;
friend class TMMesh;
friend class TMMTriangle;
friend class TMMEdge;
};
//! Edge data structure used in a triangular manifold mesh (TMM).
class TMMEdge
{
public:
TMMEdge(void);
~TMMEdge(void);
private:
size_t m_id;
CircularListElement<TMMTriangle> * m_triangles[2];
CircularListElement<TMMVertex> * m_vertices[2];
CircularListElement<TMMTriangle> * m_newFace;
TMMEdge(const TMMEdge & rhs);
friend class HACD;
friend class ICHull;
friend class TMMTriangle;
friend class TMMVertex;
friend class TMMesh;
};
//! Triangle data structure used in a triangular manifold mesh (TMM).
class TMMTriangle
{
public:
TMMTriangle(void);
~TMMTriangle(void);
private:
size_t m_id;
CircularListElement<TMMEdge> * m_edges[3];
CircularListElement<TMMVertex> * m_vertices[3];
std::set<long> m_incidentPoints;
bool m_visible;
TMMTriangle(const TMMTriangle & rhs);
friend class HACD;
friend class ICHull;
friend class TMMesh;
friend class TMMVertex;
friend class TMMEdge;
};
class Material
{
public:
Material(void);
~Material(void){}
// private:
Vec3<double> m_diffuseColor;
double m_ambientIntensity;
Vec3<double> m_specularColor;
Vec3<double> m_emissiveColor;
double m_shininess;
double m_transparency;
friend class TMMesh;
friend class HACD;
};
//! triangular manifold mesh data structure.
class TMMesh
{
public:
//! Returns the number of vertices>
inline size_t GetNVertices() const { return m_vertices.GetSize();}
//! Returns the number of edges
inline size_t GetNEdges() const { return m_edges.GetSize();}
//! Returns the number of triangles
inline size_t GetNTriangles() const { return m_triangles.GetSize();}
//! Returns the vertices circular list
inline const CircularList<TMMVertex> & GetVertices() const { return m_vertices;}
//! Returns the edges circular list
inline const CircularList<TMMEdge> & GetEdges() const { return m_edges;}
//! Returns the triangles circular list
inline const CircularList<TMMTriangle> & GetTriangles() const { return m_triangles;}
//! Returns the vertices circular list
inline CircularList<TMMVertex> & GetVertices() { return m_vertices;}
//! Returns the edges circular list
inline CircularList<TMMEdge> & GetEdges() { return m_edges;}
//! Returns the triangles circular list
inline CircularList<TMMTriangle> & GetTriangles() { return m_triangles;}
//! Add vertex to the mesh
CircularListElement<TMMVertex> * AddVertex() {return m_vertices.Add();}
//! Add vertex to the mesh
CircularListElement<TMMEdge> * AddEdge() {return m_edges.Add();}
//! Add vertex to the mesh
CircularListElement<TMMTriangle> * AddTriangle() {return m_triangles.Add();}
//! Print mesh information
void Print();
//!
void GetIFS(Vec3<Real> * const points, Vec3<long> * const triangles);
//! Save mesh
bool Save(const char *fileName);
//! Save mesh to VRML 2.0 format
bool SaveVRML2(std::ofstream &fout);
//! Save mesh to VRML 2.0 format
bool SaveVRML2(std::ofstream &fout, const Material & material);
//!
void Clear();
//!
void Copy(TMMesh & mesh);
//!
bool CheckConsistancy();
//!
bool Normalize();
//!
bool Denormalize();
//! Constructor
TMMesh(void);
//! Destructor
virtual ~TMMesh(void);
private:
CircularList<TMMVertex> m_vertices;
CircularList<TMMEdge> m_edges;
CircularList<TMMTriangle> m_triangles;
Real m_diag; //>! length of the BB diagonal
Vec3<Real> m_barycenter; //>! barycenter of the mesh
// not defined
TMMesh(const TMMesh & rhs);
friend class ICHull;
friend class HACD;
};
//! IntersectRayTriangle(): intersect a ray with a 3D triangle
//! Input: a ray R, and a triangle T
//! Output: *I = intersection point (when it exists)
//! 0 = disjoint (no intersect)
//! 1 = intersect in unique point I1
long IntersectRayTriangle( const Vec3<double> & P0, const Vec3<double> & dir,
const Vec3<double> & V0, const Vec3<double> & V1,
const Vec3<double> & V2, double &t);
// intersect_RayTriangle(): intersect a ray with a 3D triangle
// Input: a ray R, and a triangle T
// Output: *I = intersection point (when it exists)
// Return: -1 = triangle is degenerate (a segment or point)
// 0 = disjoint (no intersect)
// 1 = intersect in unique point I1
// 2 = are in the same plane
long IntersectRayTriangle2(const Vec3<double> & P0, const Vec3<double> & dir,
const Vec3<double> & V0, const Vec3<double> & V1,
const Vec3<double> & V2, double &r);
/*
Calculate the line segment PaPb that is the shortest route between
two lines P1P2 and P3P4. Calculate also the values of mua and mub where
Pa = P1 + mua (P2 - P1)
Pb = P3 + mub (P4 - P3)
Return FALSE if no solution exists.
*/
bool IntersectLineLine(const Vec3<double> & p1, const Vec3<double> & p2,
const Vec3<double> & p3, const Vec3<double> & p4,
Vec3<double> & pa, Vec3<double> & pb,
double & mua, double &mub);
}
#endif

67
extern/HACD/hacdVector.h vendored Normal file
View File

@@ -0,0 +1,67 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef HACD_VECTOR_H
#define HACD_VECTOR_H
#include<math.h>
#include<iostream>
#include "hacdVersion.h"
namespace HACD
{
typedef double Real;
//! Vector dim 3.
template < typename T > class Vec3
{
public:
T & X();
T & Y();
T & Z();
const T & X() const;
const T & Y() const;
const T & Z() const;
void Normalize();
T GetNorm() const;
void operator= (const Vec3 & rhs);
void operator+=(const Vec3 & rhs);
void operator-=(const Vec3 & rhs);
void operator-=(T a);
void operator+=(T a);
void operator/=(T a);
void operator*=(T a);
Vec3 operator^ (const Vec3 & rhs) const;
T operator* (const Vec3 & rhs) const;
Vec3 operator+ (const Vec3 & rhs) const;
Vec3 operator- (const Vec3 & rhs) const;
Vec3 operator- () const;
Vec3 operator* (T rhs) const;
Vec3 operator/ (T rhs) const;
Vec3();
Vec3(T a);
Vec3(T x, T y, T z);
Vec3(const Vec3 & rhs);
/*virtual*/ ~Vec3(void);
private:
T m_data[3];
};
template<typename T>
const bool Colinear(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c);
template<typename T>
const T Volume(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c, const Vec3<T> & d);
}
#include "hacdVector.inl" // template implementation
#endif

178
extern/HACD/hacdVector.inl vendored Normal file
View File

@@ -0,0 +1,178 @@
#pragma once
#ifndef HACD_VECTOR_INL
#define HACD_VECTOR_INL
namespace HACD
{
template <typename T>
inline Vec3<T> operator*(T lhs, const Vec3<T> & rhs)
{
return Vec3<T>(lhs * rhs.X(), lhs * rhs.Y(), lhs * rhs.Z());
}
template <typename T>
inline T & Vec3<T>::X()
{
return m_data[0];
}
template <typename T>
inline T & Vec3<T>::Y()
{
return m_data[1];
}
template <typename T>
inline T & Vec3<T>::Z()
{
return m_data[2];
}
template <typename T>
inline const T & Vec3<T>::X() const
{
return m_data[0];
}
template <typename T>
inline const T & Vec3<T>::Y() const
{
return m_data[1];
}
template <typename T>
inline const T & Vec3<T>::Z() const
{
return m_data[2];
}
template <typename T>
inline void Vec3<T>::Normalize()
{
T n = sqrt(m_data[0]*m_data[0]+m_data[1]*m_data[1]+m_data[2]*m_data[2]);
if (n != 0.0) (*this) /= n;
}
template <typename T>
inline T Vec3<T>::GetNorm() const
{
return sqrt(m_data[0]*m_data[0]+m_data[1]*m_data[1]+m_data[2]*m_data[2]);
}
template <typename T>
inline void Vec3<T>::operator= (const Vec3 & rhs)
{
this->m_data[0] = rhs.m_data[0];
this->m_data[1] = rhs.m_data[1];
this->m_data[2] = rhs.m_data[2];
}
template <typename T>
inline void Vec3<T>::operator+=(const Vec3 & rhs)
{
this->m_data[0] += rhs.m_data[0];
this->m_data[1] += rhs.m_data[1];
this->m_data[2] += rhs.m_data[2];
}
template <typename T>
inline void Vec3<T>::operator-=(const Vec3 & rhs)
{
this->m_data[0] -= rhs.m_data[0];
this->m_data[1] -= rhs.m_data[1];
this->m_data[2] -= rhs.m_data[2];
}
template <typename T>
inline void Vec3<T>::operator-=(T a)
{
this->m_data[0] -= a;
this->m_data[1] -= a;
this->m_data[2] -= a;
}
template <typename T>
inline void Vec3<T>::operator+=(T a)
{
this->m_data[0] += a;
this->m_data[1] += a;
this->m_data[2] += a;
}
template <typename T>
inline void Vec3<T>::operator/=(T a)
{
this->m_data[0] /= a;
this->m_data[1] /= a;
this->m_data[2] /= a;
}
template <typename T>
inline void Vec3<T>::operator*=(T a)
{
this->m_data[0] *= a;
this->m_data[1] *= a;
this->m_data[2] *= a;
}
template <typename T>
inline Vec3<T> Vec3<T>::operator^ (const Vec3<T> & rhs) const
{
return Vec3<T>(m_data[1] * rhs.m_data[2] - m_data[2] * rhs.m_data[1],
m_data[2] * rhs.m_data[0] - m_data[0] * rhs.m_data[2],
m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0]);
}
template <typename T>
inline T Vec3<T>::operator*(const Vec3<T> & rhs) const
{
return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1] + m_data[2] * rhs.m_data[2]);
}
template <typename T>
inline Vec3<T> Vec3<T>::operator+(const Vec3<T> & rhs) const
{
return Vec3<T>(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1],m_data[2] + rhs.m_data[2]);
}
template <typename T>
inline Vec3<T> Vec3<T>::operator-(const Vec3<T> & rhs) const
{
return Vec3<T>(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1],m_data[2] - rhs.m_data[2]) ;
}
template <typename T>
inline Vec3<T> Vec3<T>::operator-() const
{
return Vec3<T>(-m_data[0],-m_data[1],-m_data[2]) ;
}
template <typename T>
inline Vec3<T> Vec3<T>::operator*(T rhs) const
{
return Vec3<T>(rhs * this->m_data[0], rhs * this->m_data[1], rhs * this->m_data[2]);
}
template <typename T>
inline Vec3<T> Vec3<T>::operator/ (T rhs) const
{
return Vec3<T>(m_data[0] / rhs, m_data[1] / rhs, m_data[2] / rhs);
}
template <typename T>
inline Vec3<T>::Vec3(T a)
{
m_data[0] = m_data[1] = m_data[2] = a;
}
template <typename T>
inline Vec3<T>::Vec3(T x, T y, T z)
{
m_data[0] = x;
m_data[1] = y;
m_data[2] = z;
}
template <typename T>
inline Vec3<T>::Vec3(const Vec3 & rhs)
{
m_data[0] = rhs.m_data[0];
m_data[1] = rhs.m_data[1];
m_data[2] = rhs.m_data[2];
}
template <typename T>
inline Vec3<T>::~Vec3(void){};
template <typename T>
inline Vec3<T>::Vec3() {}
template<typename T>
inline const bool Colinear(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c)
{
return ((c.Z() - a.Z()) * (b.Y() - a.Y()) - (b.Z() - a.Z()) * (c.Y() - a.Y()) == 0.0 /*EPS*/) &&
((b.Z() - a.Z()) * (c.X() - a.X()) - (b.X() - a.X()) * (c.Z() - a.Z()) == 0.0 /*EPS*/) &&
((b.X() - a.X()) * (c.Y() - a.Y()) - (b.Y() - a.Y()) * (c.X() - a.X()) == 0.0 /*EPS*/);
}
template<typename T>
inline const T Volume(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c, const Vec3<T> & d)
{
return (a-d) * ((b-d) ^ (c-d));
}
}
#endif //HACD_VECTOR_INL

20
extern/HACD/hacdVersion.h vendored Normal file
View File

@@ -0,0 +1,20 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef HACD_VERSION_H
#define HACD_VERSION_H
#define HACD_VERSION_MAJOR 0
#define HACD_VERSION_MINOR 0
#endif

View File

@@ -23,6 +23,8 @@
set(INC
.
../../source/blender/gpu
../../extern/HACD
)
set(INC_SYS

View File

@@ -62,6 +62,7 @@ typedef struct rbCollisionShape rbCollisionShape;
/* Mesh Data (for Collision Shapes of Meshes) */
typedef struct rbMeshData rbMeshData;
typedef struct rbHACDMeshData rbHACDMeshData;
/* Constraint */
typedef struct rbConstraint rbConstraint;
@@ -181,6 +182,15 @@ extern void RB_body_set_angular_factor(rbRigidBody *object, float x, float y, fl
/* Kinematic State */
extern void RB_body_set_kinematic_state(rbRigidBody *body, int kinematic);
extern void RB_body_suspend(rbRigidBody *object);
extern void RB_body_set_trigger(rbRigidBody *object, int trigger);
extern void RB_body_set_ghost(rbRigidBody *object, int ghost);
extern void RB_body_set_activation_type(rbRigidBody *object, int type);
extern void RB_body_set_activation_time(rbRigidBody *object, double time);
extern void RB_body_set_activation_impulse(rbRigidBody *object, float impulse);
extern void RB_body_try_activation(rbRigidBody *object);
/* RigidBody Interface - Rigid Body Activation States */
extern int RB_body_get_activation_state(rbRigidBody *body);
extern void RB_body_set_activation_state(rbRigidBody *body, int use_deactivation);
@@ -202,8 +212,10 @@ extern void RB_body_set_scale(rbRigidBody *body, const float scale[3]);
/* Get RigidBody's position as vector */
void RB_body_get_position(rbRigidBody *body, float v_out[3]);
/* Get RigidBody's orientation as quaternion */
void RB_body_get_orientation(rbRigidBody *body, float v_out[4]);
void RB_body_get_pos_orn(rbRigidBody *object, float pos_out[3], float orn_out[4]);
void RB_body_get_compound_pos_orn(rbRigidBody *parent_object, rbCollisionShape *child_shape, float pos_out[3], float orn_out[4]);
/* ............ */
@@ -214,11 +226,11 @@ extern void RB_body_apply_central_force(rbRigidBody *body, const float v_in[3]);
/* Setup (Standard Shapes) ----------- */
extern rbCollisionShape *RB_shape_new_box(float x, float y, float z);
extern rbCollisionShape *RB_shape_new_sphere(float radius);
extern rbCollisionShape *RB_shape_new_capsule(float radius, float height);
extern rbCollisionShape *RB_shape_new_cone(float radius, float height);
extern rbCollisionShape *RB_shape_new_cylinder(float radius, float height);
extern rbCollisionShape *RB_shape_new_box(float x, float y, float z, const float loc[3], const float rot[4], const float center[3]);
extern rbCollisionShape *RB_shape_new_sphere(float radius, const float loc[3], const float rot[4], const float center[3]);
extern rbCollisionShape *RB_shape_new_capsule(float radius, float height, const float loc[3], const float rot[4], const float center[3]);
extern rbCollisionShape *RB_shape_new_cone(float radius, float height, const float loc[3], const float rot[4], const float center[3]);
extern rbCollisionShape *RB_shape_new_cylinder(float radius, float height, const float loc[3], const float rot[4], const float center[3]);
/* Setup (Convex Hull) ------------ */
@@ -227,14 +239,25 @@ extern rbCollisionShape *RB_shape_new_convex_hull(float *verts, int stride, int
/* Setup (Triangle Mesh) ---------- */
/* 1 */
extern rbMeshData *RB_trimesh_data_new(void);
extern void RB_trimesh_add_triangle(rbMeshData *mesh, const float v1[3], const float v2[3], const float v3[3]);
extern rbMeshData *RB_trimesh_data_new(int num_tris, int num_verts);
extern void RB_trimesh_add_vertices(rbMeshData *mesh, float *vertices, int num_verts, int vert_stride);
extern void RB_trimesh_add_triangle_indices(rbMeshData *mesh, int num, int index0, int index1, int index2);
extern void RB_trimesh_finish(rbMeshData *mesh);
/* 2a - Triangle Meshes */
extern rbCollisionShape *RB_shape_new_trimesh(rbMeshData *mesh);
/* 2b - GImpact Meshes */
extern rbCollisionShape *RB_shape_new_gimpact_mesh(rbMeshData *mesh);
extern rbHACDMeshData *RB_hacd_mesh_new(int num_tris, int num_verts);
extern void RB_hacd_mesh_add_triangle(rbHACDMeshData *mesh, const float v1[3], const float v2[3], const float v3[3]);
extern rbCollisionShape *RB_shape_new_convex_decomp(rbHACDMeshData *mesh);
/* Compound Shapes ------------------- */
extern void RB_shape_add_compound_child(rbRigidBody *parent, rbCollisionShape *child, float child_pos[3], float child_orn[4]);
/* Cleanup --------------------------- */
extern void RB_shape_delete(rbCollisionShape *shape);
@@ -245,6 +268,8 @@ extern void RB_shape_delete(rbCollisionShape *shape);
extern float RB_shape_get_margin(rbCollisionShape *shape);
extern void RB_shape_set_margin(rbCollisionShape *shape, float value);
extern void RB_shape_trimesh_update(rbCollisionShape *shape, float *vertices, int num_verts, int vert_stride, float min[3], float max[3]);
/* ********************************** */
/* Constraints */

View File

@@ -59,6 +59,8 @@ subject to the following restrictions:
#include <stdio.h>
#include <errno.h>
#include "GPU_draw.h"
#include "RBI_api.h"
#include "btBulletDynamicsCommon.h"
@@ -73,6 +75,10 @@ subject to the following restrictions:
#include "BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h"
#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h"
#include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h>
#include "hacdHACD.h"
struct rbDynamicsWorld {
btDiscreteDynamicsWorld *dynamicsWorld;
btDefaultCollisionConfiguration *collisionConfiguration;
@@ -80,15 +86,47 @@ struct rbDynamicsWorld {
btBroadphaseInterface *pairCache;
btConstraintSolver *constraintSolver;
btOverlapFilterCallback *filterCallback;
double elapsed_time;
};
enum ActivationType {
ACTIVATION_COLLISION = 0,
ACTIVATION_TRIGGER,
ACTIVATION_TIME
};
struct rbRigidBody {
btRigidBody *body;
rbDynamicsWorld *world;
int col_groups;
bool is_trigger;
bool suspended;
float saved_mass;
double activation_time;
float activation_impulse;
int activation_type;
};
struct rbVert {
float x, y, z;
};
struct rbTri {
int v0, v1, v2;
};
struct rbMeshData {
btTriangleIndexVertexArray *index_array;
rbVert *vertices;
rbTri *triangles;
int num_vertices;
int num_triangles;
};
struct rbCollisionShape {
btCollisionShape *cshape;
btTriangleMesh *mesh;
btCollisionShape *compound;
rbMeshData *mesh;
btTriangleInfoMap *triangle_info_map;
};
struct rbFilterCallback : public btOverlapFilterCallback
@@ -99,14 +137,158 @@ struct rbFilterCallback : public btOverlapFilterCallback
rbRigidBody *rb1 = (rbRigidBody *)((btRigidBody *)proxy1->m_clientObject)->getUserPointer();
bool collides;
collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
bool rb0_kinematic = ((btRigidBody *)proxy0->m_clientObject)->isKinematicObject();
bool rb1_kinematic = ((btRigidBody *)proxy1->m_clientObject)->isKinematicObject();
/* allow static-static collision so suspended bodies can be activated by kinematic objects */
if ((rb0->suspended && rb1_kinematic) || (rb1->suspended && rb0_kinematic)) {
collides = true;
}
else {
collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
}
collides = collides && (rb0->col_groups & rb1->col_groups);
return collides;
}
};
static inline void activate(rbRigidBody *rb)
{
btRigidBody *body = rb->body;
rb->suspended = false;
rb->world->dynamicsWorld->removeRigidBody(body);
RB_body_set_mass(rb, rb->saved_mass);
rb->world->dynamicsWorld->addRigidBody(body);
body->activate();
}
static inline void activate_on_impulse(btPersistentManifold *manifold, rbRigidBody *rb0, rbRigidBody *rb1)
{
if (rb0->activation_impulse > 0.0f) {
float impulse = 0.0f;
/* use contact with highest impulse */
for (int i = 0; i < manifold->getNumContacts(); i++) {
btScalar velocity = (rb1->body->getLinearVelocity() + rb1->body->getAngularVelocity()).dot(-manifold->getContactPoint(i).m_normalWorldOnB);
impulse = (impulse < velocity) ? velocity : impulse;
}
impulse /= rb1->body->getInvMass();
if (impulse >= rb0->activation_impulse)
activate(rb0);
}
else {
activate(rb0);
}
}
static inline void handle_activation(btPersistentManifold *manifold, rbRigidBody *rb0, rbRigidBody *rb1)
{
if (rb0->suspended) {
switch(rb0->activation_type) {
case ACTIVATION_COLLISION:
activate_on_impulse(manifold, rb0, rb1);
break;
case ACTIVATION_TRIGGER:
if (rb1->is_trigger) {
activate_on_impulse(manifold, rb0, rb1);
}
break;
}
}
}
static void nearCallback(btBroadphasePair &collisionPair, btCollisionDispatcher &dispatcher, const btDispatcherInfo &dispatchInfo)
{
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
if (dispatcher.needsCollision(colObj0, colObj1)) {
btCollisionObjectWrapper obj0Wrap(0, colObj0->getCollisionShape(), colObj0,colObj0->getWorldTransform(), -1, -1);
btCollisionObjectWrapper obj1Wrap(0, colObj1->getCollisionShape(), colObj1,colObj1->getWorldTransform(), -1, -1);
//dispatcher will keep algorithms persistent in the collision pair
if (!collisionPair.m_algorithm) {
collisionPair.m_algorithm = dispatcher.findAlgorithm(&obj0Wrap, &obj1Wrap);
}
if (collisionPair.m_algorithm) {
btManifoldResult contactPointResult(&obj0Wrap, &obj1Wrap);
if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE) {
//discrete collision detection query
collisionPair.m_algorithm->processCollision(&obj0Wrap, &obj1Wrap, dispatchInfo, &contactPointResult);
}
else {
//continuous collision detection query, time of impact (toi)
btScalar toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0, colObj1, dispatchInfo, &contactPointResult);
if (dispatchInfo.m_timeOfImpact > toi)
dispatchInfo.m_timeOfImpact = toi;
}
btPersistentManifold *manifold = contactPointResult.getPersistentManifold();
if (manifold && manifold->getNumContacts() > 0) {
rbRigidBody *rb0 = (rbRigidBody *)((btRigidBody *)collisionPair.m_pProxy0->m_clientObject)->getUserPointer();
rbRigidBody *rb1 = (rbRigidBody *)((btRigidBody *)collisionPair.m_pProxy1->m_clientObject)->getUserPointer();
handle_activation(manifold, rb0, rb1);
handle_activation(manifold, rb1, rb0);
}
}
}
}
static bool contactAddedCallback(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1)
{
btAdjustInternalEdgeContacts(cp, colObj1Wrap, colObj0Wrap, partId1, index1);
return true;
}
class rbDebugDraw : public btIDebugDraw {
private:
int debug_mode;
public:
rbDebugDraw() { }
virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color)
{
float root[3] = {from.x(), from.y(), from.z()};
float tip[3] = {to.x(), to.y(), to.z()};
float col[3] = {color.x(), color.y(), color.z()};
GPU_debug_add_line(root, tip, col);
}
virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color)
{
float root[3] = {PointOnB.x(), PointOnB.y(), PointOnB.z()};
btVector3 to = PointOnB + normalOnB;
float nor_tip[3] = {to.x(), to.y(), to.z()};
float col[3] = {0.0f, 1.0f, 1.0f};
GPU_debug_add_point(root, col);
col[0] = 1.0f;
col[1] = 0.0f;
col[2] = 1.0f;
GPU_debug_add_line(root, nor_tip, col);
}
virtual void reportErrorWarning(const char *warningString)
{
}
virtual void draw3dText(const btVector3& location,const char *textString)
{
}
virtual void setDebugMode(int debugMode)
{
debug_mode = debugMode;
}
virtual int getDebugMode() const
{
return debug_mode;
}
};
static inline void copy_v3_btvec3(float vec[3], const btVector3 &btvec)
{
vec[0] = (float)btvec[0];
@@ -135,6 +317,7 @@ rbDynamicsWorld *RB_dworld_new(const float gravity[3])
world->dispatcher = new btCollisionDispatcher(world->collisionConfiguration);
btGImpactCollisionAlgorithm::registerAlgorithm((btCollisionDispatcher *)world->dispatcher);
((btCollisionDispatcher *)world->dispatcher)->setNearCallback(nearCallback);
world->pairCache = new btDbvtBroadphase();
@@ -152,6 +335,22 @@ rbDynamicsWorld *RB_dworld_new(const float gravity[3])
RB_dworld_set_gravity(world, gravity);
// gContactAddedCallback = contactAddedCallback;
world->elapsed_time = 0.0;
// HACK set debug drawer, this is only temporary
btIDebugDraw *debugDrawer = new rbDebugDraw();
debugDrawer->setDebugMode(btIDebugDraw::DBG_DrawWireframe |
btIDebugDraw::DBG_DrawAabb |
btIDebugDraw::DBG_DrawContactPoints |
btIDebugDraw::DBG_DrawText |
btIDebugDraw::DBG_DrawConstraintLimits |
btIDebugDraw::DBG_DrawConstraints |
btIDebugDraw::DBG_DrawConstraintLimits
);
world->dynamicsWorld->setDebugDrawer(debugDrawer);
return world;
}
@@ -200,7 +399,12 @@ void RB_dworld_set_split_impulse(rbDynamicsWorld *world, int split_impulse)
void RB_dworld_step_simulation(rbDynamicsWorld *world, float timeStep, int maxSubSteps, float timeSubStep)
{
world->elapsed_time += timeStep;
world->dynamicsWorld->stepSimulation(timeStep, maxSubSteps, timeSubStep);
// draw debug information
GPU_debug_reset();
world->dynamicsWorld->debugDrawWorld();
}
/* Export -------------------------- */
@@ -237,6 +441,7 @@ void RB_dworld_add_body(rbDynamicsWorld *world, rbRigidBody *object, int col_gro
{
btRigidBody *body = object->body;
object->col_groups = col_groups;
object->world = world;
world->dynamicsWorld->addRigidBody(body);
}
@@ -312,12 +517,18 @@ rbRigidBody *RB_body_new(rbCollisionShape *shape, const float loc[3], const floa
btDefaultMotionState *motionState = new btDefaultMotionState(trans);
/* make rigidbody */
btRigidBody::btRigidBodyConstructionInfo rbInfo(1.0f, motionState, shape->cshape);
btRigidBody::btRigidBodyConstructionInfo rbInfo(1.0f, motionState, shape->compound);
object->body = new btRigidBody(rbInfo);
object->body->setUserPointer(object);
object->is_trigger = false;
object->suspended = false;
if (shape->cshape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE)
object->body->setCollisionFlags(object->body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
return object;
}
@@ -352,7 +563,7 @@ void RB_body_set_collision_shape(rbRigidBody *object, rbCollisionShape *shape)
btRigidBody *body = object->body;
/* set new collision shape */
body->setCollisionShape(shape->cshape);
body->setCollisionShape(shape->compound);
/* recalculate inertia, since that depends on the collision shape... */
RB_body_set_mass(object, RB_body_get_mass(object));
@@ -385,9 +596,10 @@ void RB_body_set_mass(rbRigidBody *object, float value)
btCollisionShape *shape = body->getCollisionShape();
shape->calculateLocalInertia(value, localInertia);
}
body->setMassProps(value, localInertia);
body->updateInertiaTensor();
if (!object->suspended) {
body->setMassProps(value, localInertia);
body->updateInertiaTensor();
}
}
@@ -521,6 +733,8 @@ void RB_body_set_angular_factor(rbRigidBody *object, float x, float y, float z)
void RB_body_set_kinematic_state(rbRigidBody *object, int kinematic)
{
if (object->suspended)
return;
btRigidBody *body = object->body;
if (kinematic)
body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
@@ -528,6 +742,48 @@ void RB_body_set_kinematic_state(rbRigidBody *object, int kinematic)
body->setCollisionFlags(body->getCollisionFlags() & ~btCollisionObject::CF_KINEMATIC_OBJECT);
}
void RB_body_suspend(rbRigidBody *object)
{
object->saved_mass = RB_body_get_mass(object);
RB_body_set_mass(object, 0.0f);
object->suspended = true;
}
void RB_body_set_trigger(rbRigidBody *object, int trigger)
{
object->is_trigger = trigger;
}
void RB_body_set_ghost(rbRigidBody *object, int ghost)
{
btRigidBody *body = object->body;
if (ghost)
body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE);
else
body->setCollisionFlags(body->getCollisionFlags() & ~btCollisionObject::CF_NO_CONTACT_RESPONSE);
}
void RB_body_set_activation_type(rbRigidBody *object, int type)
{
object->activation_type = type;
}
void RB_body_set_activation_time(rbRigidBody *object, double time)
{
object->activation_time = time;
}
void RB_body_set_activation_impulse(rbRigidBody *object, float impulse)
{
object->activation_impulse = impulse;
}
void RB_body_try_activation(rbRigidBody *object)
{
if (object->suspended && object->activation_time <= object->world->elapsed_time)
activate(object);
}
/* ............ */
void RB_body_set_activation_state(rbRigidBody *object, int use_deactivation)
@@ -608,11 +864,31 @@ void RB_body_get_position(rbRigidBody *object, float v_out[3])
copy_v3_btvec3(v_out, body->getWorldTransform().getOrigin());
}
void RB_body_get_orientation(rbRigidBody *object, float v_out[4])
void RB_body_get_pos_orn(rbRigidBody *object, float pos_out[3], float orn_out[4])
{
btRigidBody *body = object->body;
copy_quat_btquat(v_out, body->getWorldTransform().getRotation());
copy_v3_btvec3(pos_out, body->getWorldTransform().getOrigin());
copy_quat_btquat(orn_out, body->getWorldTransform().getRotation());
}
void RB_body_get_compound_pos_orn(rbRigidBody *parent_object, rbCollisionShape *child_shape, float pos_out[3], float orn_out[4])
{
btRigidBody *body = parent_object->body;
btCompoundShape *compound = (btCompoundShape*)body->getCollisionShape();
btTransform transform = body->getWorldTransform();
btTransform child_transform;
for (int i = 0; i < compound->getNumChildShapes(); i++) {
if (child_shape->compound == compound->getChildShape(i)) {
child_transform = compound->getChildTransform(i);
break;
}
}
transform *= child_transform;
copy_v3_btvec3(pos_out, transform.getOrigin());
copy_quat_btquat(orn_out, transform.getRotation());
}
/* ............ */
@@ -630,44 +906,54 @@ void RB_body_apply_central_force(rbRigidBody *object, const float v_in[3])
/* Setup (Standard Shapes) ----------- */
rbCollisionShape *RB_shape_new_box(float x, float y, float z)
static rbCollisionShape *prepare_primitive_shape(btCollisionShape *cshape, const float loc[3], const float rot[4], const float center[3])
{
rbCollisionShape *shape = new rbCollisionShape;
shape->cshape = new btBoxShape(btVector3(x, y, z));
shape->cshape = cshape;
shape->mesh = NULL;
shape->triangle_info_map = NULL;
btTransform world_transform = btTransform();
world_transform.setIdentity();
world_transform.setOrigin(btVector3(loc[0], loc[1], loc[2]));
world_transform.setRotation(btQuaternion(rot[1], rot[2], rot[3], rot[0]));
shape->compound = new btCompoundShape();
btTransform compound_transform;
compound_transform.setIdentity();
/* adjust center of mass */
compound_transform.setOrigin(btVector3(center[0], center[1], center[2]));
compound_transform.setRotation(btQuaternion(rot[1], rot[2], rot[3], rot[0]));
compound_transform = world_transform.inverse() * compound_transform;
((btCompoundShape*)shape->compound)->addChildShape(compound_transform, shape->cshape);
return shape;
}
rbCollisionShape *RB_shape_new_sphere(float radius)
rbCollisionShape *RB_shape_new_box(float x, float y, float z, const float loc[3], const float rot[4], const float center[3])
{
rbCollisionShape *shape = new rbCollisionShape;
shape->cshape = new btSphereShape(radius);
shape->mesh = NULL;
return shape;
return prepare_primitive_shape(new btBoxShape(btVector3(x, y, z)), loc, rot, center);
}
rbCollisionShape *RB_shape_new_capsule(float radius, float height)
rbCollisionShape *RB_shape_new_sphere(float radius, const float loc[3], const float rot[4], const float center[3])
{
rbCollisionShape *shape = new rbCollisionShape;
shape->cshape = new btCapsuleShapeZ(radius, height);
shape->mesh = NULL;
return shape;
return prepare_primitive_shape(new btSphereShape(radius), loc, rot, center);
}
rbCollisionShape *RB_shape_new_cone(float radius, float height)
rbCollisionShape *RB_shape_new_capsule(float radius, float height, const float loc[3], const float rot[4], const float center[3])
{
rbCollisionShape *shape = new rbCollisionShape;
shape->cshape = new btConeShapeZ(radius, height);
shape->mesh = NULL;
return shape;
return prepare_primitive_shape(new btCapsuleShapeZ(radius, height), loc, rot, center);
}
rbCollisionShape *RB_shape_new_cylinder(float radius, float height)
rbCollisionShape *RB_shape_new_cone(float radius, float height, const float loc[3], const float rot[4], const float center[3])
{
rbCollisionShape *shape = new rbCollisionShape;
shape->cshape = new btCylinderShapeZ(btVector3(radius, radius, height));
shape->mesh = NULL;
return shape;
return prepare_primitive_shape(new btConeShapeZ(radius, height), loc, rot, center);
}
rbCollisionShape *RB_shape_new_cylinder(float radius, float height, const float loc[3], const float rot[4], const float center[3])
{
return prepare_primitive_shape(new btCylinderShapeZ(btVector3(radius, radius, height)), loc, rot, center);
}
/* Setup (Convex Hull) ------------ */
@@ -687,65 +973,203 @@ rbCollisionShape *RB_shape_new_convex_hull(float *verts, int stride, int count,
shape->cshape = hull_shape;
shape->mesh = NULL;
shape->triangle_info_map = NULL;
shape->compound = new btCompoundShape();
btTransform compound_transform;
compound_transform.setIdentity();
((btCompoundShape*)shape->compound)->addChildShape(compound_transform, shape->cshape);
return shape;
}
/* Setup (Triangle Mesh) ---------- */
/* Need to call rbTriMeshNewData() followed by rbTriMeshAddTriangle() several times
* to set up the mesh buffer BEFORE calling rbShapeNewTriMesh(). Otherwise,
* we get nasty crashes...
*/
/* Need to call RB_trimesh_finish() after creating triangle mesh and adding vertices and triangles */
rbMeshData *RB_trimesh_data_new()
rbMeshData *RB_trimesh_data_new(int num_tris, int num_verts)
{
// XXX: welding threshold?
return (rbMeshData *) new btTriangleMesh(true, false);
rbMeshData *mesh = new rbMeshData;
mesh->vertices = new rbVert[num_verts];
mesh->triangles = new rbTri[num_tris];
mesh->num_vertices = num_verts;
mesh->num_triangles = num_tris;
return mesh;
}
void RB_trimesh_add_triangle(rbMeshData *mesh, const float v1[3], const float v2[3], const float v3[3])
static void RB_trimesh_data_delete(rbMeshData *mesh)
{
btTriangleMesh *meshData = reinterpret_cast<btTriangleMesh*>(mesh);
/* cast vertices to usable forms for Bt-API */
btVector3 vtx1((btScalar)v1[0], (btScalar)v1[1], (btScalar)v1[2]);
btVector3 vtx2((btScalar)v2[0], (btScalar)v2[1], (btScalar)v2[2]);
btVector3 vtx3((btScalar)v3[0], (btScalar)v3[1], (btScalar)v3[2]);
/* add to the mesh
* - remove duplicated verts is enabled
*/
meshData->addTriangle(vtx1, vtx2, vtx3, false);
delete mesh->index_array;
delete mesh->vertices;
delete mesh->triangles;
delete mesh;
}
void RB_trimesh_add_vertices(rbMeshData *mesh, float *vertices, int num_verts, int vert_stride)
{
for (int i = 0; i < num_verts; i++) {
float *vert = (float*)(((char*)vertices + i * vert_stride));
mesh->vertices[i].x = vert[0];
mesh->vertices[i].y = vert[1];
mesh->vertices[i].z = vert[2];
}
}
void RB_trimesh_add_triangle_indices(rbMeshData *mesh, int num, int index0, int index1, int index2)
{
mesh->triangles[num].v0 = index0;
mesh->triangles[num].v1 = index1;
mesh->triangles[num].v2 = index2;
}
void RB_trimesh_finish(rbMeshData *mesh)
{
mesh->index_array = new btTriangleIndexVertexArray(mesh->num_triangles, (int*)mesh->triangles, sizeof(rbTri),
mesh->num_vertices, (float*)mesh->vertices, sizeof(rbVert));
}
rbCollisionShape *RB_shape_new_trimesh(rbMeshData *mesh)
{
rbCollisionShape *shape = new rbCollisionShape;
btTriangleMesh *tmesh = reinterpret_cast<btTriangleMesh*>(mesh);
/* triangle-mesh we create is a BVH wrapper for triangle mesh data (for faster lookups) */
// RB_TODO perhaps we need to allow saving out this for performance when rebuilding?
btBvhTriangleMeshShape *unscaledShape = new btBvhTriangleMeshShape(tmesh, true, true);
btBvhTriangleMeshShape *unscaledShape = new btBvhTriangleMeshShape(mesh->index_array, true, true);
shape->triangle_info_map = new btTriangleInfoMap();
// btGenerateInternalEdgeInfo(unscaledShape, shape->triangle_info_map);
shape->cshape = new btScaledBvhTriangleMeshShape(unscaledShape, btVector3(1.0f, 1.0f, 1.0f));
shape->mesh = tmesh;
shape->mesh = mesh;
shape->compound = new btCompoundShape();
btTransform compound_transform;
compound_transform.setIdentity();
((btCompoundShape*)shape->compound)->addChildShape(compound_transform, shape->cshape);
return shape;
}
void RB_shape_trimesh_update(rbCollisionShape *shape, float *vertices, int num_verts, int vert_stride, float min[3], float max[3])
{
if (shape->mesh == NULL || num_verts != shape->mesh->num_vertices)
return;
for (int i = 0; i < num_verts; i++) {
float *vert = (float*)(((char*)vertices + i * vert_stride));
shape->mesh->vertices[i].x = vert[0];
shape->mesh->vertices[i].y = vert[1];
shape->mesh->vertices[i].z = vert[2];
}
if (shape->cshape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) {
btScaledBvhTriangleMeshShape *scaled_shape = (btScaledBvhTriangleMeshShape *)shape->cshape;
btBvhTriangleMeshShape *mesh_shape = scaled_shape->getChildShape();
mesh_shape->refitTree(btVector3(min[0], min[1], min[2]), btVector3(max[0], max[1], max[2]));
}
else if (shape->cshape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE) {
btGImpactMeshShape *mesh_shape = (btGImpactMeshShape*)shape->cshape;
mesh_shape->updateBound();
}
}
rbCollisionShape *RB_shape_new_gimpact_mesh(rbMeshData *mesh)
{
rbCollisionShape *shape = new rbCollisionShape;
/* interpret mesh buffer as btTriangleIndexVertexArray (i.e. an impl of btStridingMeshInterface) */
btTriangleMesh *tmesh = reinterpret_cast<btTriangleMesh*>(mesh);
btGImpactMeshShape *gimpactShape = new btGImpactMeshShape(tmesh);
btGImpactMeshShape *gimpactShape = new btGImpactMeshShape(mesh->index_array);
gimpactShape->updateBound(); // TODO: add this to the update collision margin call?
shape->cshape = gimpactShape;
shape->mesh = tmesh;
shape->mesh = mesh;
shape->triangle_info_map = NULL;
shape->compound = new btCompoundShape();
btTransform compound_transform;
compound_transform.setIdentity();
((btCompoundShape*)shape->compound)->addChildShape(compound_transform, shape->cshape);
return shape;
}
struct rbHACDMeshData {
std::vector< HACD::Vec3<HACD::Real> > verts;
std::vector< HACD::Vec3<long> > tris;
};
rbHACDMeshData *RB_hacd_mesh_new(int num_tris, int num_verts)
{
rbHACDMeshData *mesh = new rbHACDMeshData;
mesh->verts.reserve(num_verts);
mesh->tris.reserve(num_tris);
return mesh;
}
void RB_hacd_mesh_add_triangle(rbHACDMeshData *mesh, const float v1[3], const float v2[3], const float v3[3])
{
mesh->tris.push_back(HACD::Vec3<long>(mesh->verts.size(), mesh->verts.size()+1, mesh->verts.size()+2));
mesh->verts.push_back(HACD::Vec3<HACD::Real>(v1[0], v1[1], v1[2]));
mesh->verts.push_back(HACD::Vec3<HACD::Real>(v2[0], v2[1], v2[2]));
mesh->verts.push_back(HACD::Vec3<HACD::Real>(v3[0], v3[1], v3[2]));
}
rbCollisionShape *RB_shape_new_convex_decomp(rbHACDMeshData *mesh)
{
rbCollisionShape *shape = new rbCollisionShape;
btCompoundShape *compound = new btCompoundShape();
HACD::HACD hacd;
hacd.SetPoints(&mesh->verts[0]);
hacd.SetNPoints(mesh->verts.size());
hacd.SetTriangles(&mesh->tris[0]);
hacd.SetNTriangles(mesh->tris.size());
hacd.Compute();
int num_clusters = hacd.GetNClusters();
for (int i = 0; i < num_clusters; i++) {
int num_verts = hacd.GetNPointsCH(i);
int num_tris = hacd.GetNTrianglesCH(i);
HACD::Vec3<HACD::Real> verts[num_verts];
HACD::Vec3<long> tris[num_tris];
hacd.GetCH(i, verts, tris);
btVector3 hull_verts[num_verts];
for (int i = 0; i < num_verts; i++) {
hull_verts[i].setX(verts[i].X());
hull_verts[i].setY(verts[i].Y());
hull_verts[i].setZ(verts[i].Z());
}
btTransform transform;
transform.setIdentity();
btConvexHullShape *hull = new btConvexHullShape(&hull_verts[0].getX(), num_verts);
compound->addChildShape(transform, hull);
}
shape->mesh = NULL;
shape->triangle_info_map = NULL;
shape->compound = compound;
shape->cshape = compound;
delete mesh;
return shape;
}
void RB_shape_add_compound_child(rbRigidBody *parent, rbCollisionShape *child, float child_pos[3], float child_orn[4])
{
btCompoundShape *compound = (btCompoundShape*)parent->body->getCollisionShape();
btTransform parent_transform = parent->body->getCenterOfMassTransform(); // TODO center of mass?
btTransform transform;
transform.setOrigin(btVector3(child_pos[0], child_pos[1], child_pos[2]));
transform.setRotation(btQuaternion(child_orn[1], child_orn[2], child_orn[3], child_orn[0]));
transform = parent_transform.inverse() * transform;
compound->addChildShape(transform, child->compound);
}
/* Cleanup --------------------------- */
void RB_shape_delete(rbCollisionShape *shape)
@@ -756,8 +1180,12 @@ void RB_shape_delete(rbCollisionShape *shape)
delete child_shape;
}
if (shape->mesh)
delete shape->mesh;
delete shape->cshape;
RB_trimesh_data_delete(shape->mesh);
if (shape->triangle_info_map)
delete shape->triangle_info_map;
if (shape->cshape != shape->compound)
delete shape->cshape;
delete shape->compound;
delete shape;
}

View File

@@ -19,6 +19,7 @@
# <pep8 compliant>
import bpy
from bpy.types import Panel
from bl_ui.properties_physics_common import effector_weights_ui
class PHYSICS_PT_rigidbody_panel():
@@ -44,10 +45,14 @@ class PHYSICS_PT_rigid_body(PHYSICS_PT_rigidbody_panel, Panel):
if rbo is not None:
layout.prop(rbo, "type", text="Type")
row = layout.row()
split = layout.split()
col = split.column()
if rbo.type == 'ACTIVE':
row.prop(rbo, "enabled", text="Dynamic")
row.prop(rbo, "kinematic", text="Animated")
col.prop(rbo, "enabled", text="Dynamic")
col.prop(rbo, "kinematic", text="Animated")
col = split.column()
col.prop(rbo, "trigger", text="Trigger")
col.prop(rbo, "ghost", text="Ghost")
if rbo.type == 'ACTIVE':
layout.prop(rbo, "mass")
@@ -69,6 +74,12 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel):
rbo = ob.rigid_body
layout.prop(rbo, "collision_shape", text="Shape")
if rbo.collision_shape in {'MESH', 'CONVEX_HULL', 'APPROX'}:
layout.prop(rbo, "mesh_source", text="Source")
if rbo.collision_shape == 'MESH' and rbo.mesh_source == 'DEFORM':
layout.prop(rbo, "use_deform", text="Deforming")
split = layout.split()
@@ -107,26 +118,49 @@ class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel):
ob = context.object
rbo = ob.rigid_body
#col = layout.column(align=1)
#col.label(text="Activation:")
# XXX: settings such as activate on collison/etc.
split = layout.split()
col = split.column()
col.label(text="Activation:")
col.prop(rbo, "use_start_deactivated")
sub = col.column()
sub.active = rbo.use_start_deactivated
sub.prop(rbo, "activation_type", text="Type")
if rbo.activation_type == 'TIME':
sub.prop(rbo, "activation_time", text="Time")
elif rbo.activation_type in {'COLLISION', 'TRIGGER'}:
sub.prop(rbo, "activation_impulse", text="Threshold")
col = split.column()
col.label(text="Deactivation:")
col.prop(rbo, "use_deactivation")
sub = col.column()
sub.active = rbo.use_deactivation
sub.prop(rbo, "use_start_deactivated")
sub.prop(rbo, "deactivate_linear_velocity", text="Linear Vel")
sub.prop(rbo, "deactivate_angular_velocity", text="Angular Vel")
# TODO: other params such as time?
col = split.column()
col = layout.column()
col.label(text="Damping:")
col.prop(rbo, "linear_damping", text="Translation")
col.prop(rbo, "angular_damping", text="Rotation")
class PHYSICS_PT_rigid_body_field_weights(PHYSICS_PT_rigidbody_panel, Panel):
bl_label = "Rigid Body Field Weights"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
@classmethod
def poll(cls, context):
obj = context.object
return (obj and obj.rigid_body and
obj.rigid_body.type == 'ACTIVE' and
(not context.scene.render.use_game_engine))
def draw(self, context):
ob = context.object
rbo = ob.rigid_body
effector_weights_ui(self, context, rbo.effector_weights, 'RIGID_BODY')
if __name__ == "__main__": # only for live edit.
bpy.utils.register_module(__name__)

View File

@@ -2741,6 +2741,7 @@ class VIEW3D_PT_view3d_display(Panel):
col.prop(view, "show_outline_selected")
col.prop(view, "show_all_objects_origin")
col.prop(view, "show_relationship_lines")
col.prop(view, "show_physics")
col = layout.column()
col.active = display_all

View File

@@ -67,10 +67,7 @@ struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw);
void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw);
/* 'validate' (i.e. make new or replace old) Physics-Engine objects */
void BKE_rigidbody_validate_sim_world(struct Scene *scene, struct RigidBodyWorld *rbw, short rebuild);
void BKE_rigidbody_validate_sim_object(struct RigidBodyWorld *rbw, struct Object *ob, short rebuild);
void BKE_rigidbody_validate_sim_shape(struct Object *ob, short rebuild);
void BKE_rigidbody_validate_sim_constraint(struct RigidBodyWorld *rbw, struct Object *ob, short rebuild);
void BKE_rigidbody_validate_sim_world(struct Scene *scene, struct RigidBodyWorld *rbw, bool rebuild);
/* -------------- */
/* Utilities */

View File

@@ -1009,8 +1009,12 @@ static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int UNUS
if (rbo->type == RBO_TYPE_ACTIVE) {
#ifdef WITH_BULLET
RB_body_get_position(rbo->physics_object, rbo->pos);
RB_body_get_orientation(rbo->physics_object, rbo->orn);
if (ob->parent && ob->parent->rigidbody_object && ob->parent->flag) {
RB_body_get_compound_pos_orn(ob->parent->rigidbody_object->physics_object, rbo->physics_shape, rbo->pos, rbo->orn);
}
else {
RB_body_get_pos_orn(rbo->physics_object, rbo->pos, rbo->orn);
}
#endif
PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, rbo->pos);
PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, rbo->orn);

View File

@@ -144,6 +144,10 @@ void BKE_rigidbody_free_object(Object *ob)
rbo->physics_shape = NULL;
}
/* free effector weights */
if (rbo->effector_weights)
MEM_freeN(rbo->effector_weights);
/* free data itself */
MEM_freeN(rbo);
ob->rigidbody_object = NULL;
@@ -178,11 +182,15 @@ void BKE_rigidbody_free_constraint(Object *ob)
RigidBodyOb *BKE_rigidbody_copy_object(Object *ob)
{
RigidBodyOb *rbo = ob->rigidbody_object;
RigidBodyOb *rboN = NULL;
if (ob->rigidbody_object) {
if (rbo) {
/* just duplicate the whole struct first (to catch all the settings) */
rboN = MEM_dupallocN(ob->rigidbody_object);
rboN = MEM_dupallocN(rbo);
if (rbo->effector_weights)
rboN->effector_weights = MEM_dupallocN(rbo->effector_weights);
/* tag object as needing to be verified */
rboN->flag |= RBO_FLAG_NEEDS_VALIDATE;
@@ -225,26 +233,47 @@ void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc)
/* ************************************** */
/* Setup Utilities - Validate Sim Instances */
/* get the appropriate DerivedMesh based on rigid body mesh source */
static DerivedMesh *rigidbody_get_mesh(Object *ob)
{
if (ob->rigidbody_object->mesh_source == RBO_MESH_DEFORM) {
return ob->derivedDeform;
}
else if (ob->rigidbody_object->mesh_source == RBO_MESH_FINAL) {
return ob->derivedFinal;
}
else {
return CDDM_from_mesh(ob->data, ob);
}
}
/* create collision shape of mesh - convex hull */
static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, float margin, bool *can_embed)
{
rbCollisionShape *shape = NULL;
Mesh *me = NULL;
DerivedMesh *dm = NULL;
MVert *mvert = NULL;
int totvert = 0;
if (ob->type == OB_MESH && ob->data) {
me = ob->data;
dm = rigidbody_get_mesh(ob);
mvert = (dm) ? dm->getVertArray(dm) : NULL;
totvert = (dm) ? dm->getNumVerts(dm) : 0;
}
else {
printf("ERROR: cannot make Convex Hull collision shape for non-Mesh object\n");
}
if (me && me->totvert) {
shape = RB_shape_new_convex_hull((float *)me->mvert, sizeof(MVert), me->totvert, margin, can_embed);
if (totvert) {
shape = RB_shape_new_convex_hull((float *)mvert, sizeof(MVert), totvert, margin, can_embed);
}
else {
printf("ERROR: no vertices to define Convex Hull collision shape with\n");
}
if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE)
dm->release(dm);
return shape;
}
@@ -256,14 +285,20 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
rbCollisionShape *shape = NULL;
if (ob->type == OB_MESH) {
DerivedMesh *dm = CDDM_from_mesh(ob->data, ob);
DerivedMesh *dm = NULL;
MVert *mvert;
MFace *mface;
int totvert;
int totface;
int tottris = 0;
int triangle_index = 0;
dm = rigidbody_get_mesh(ob);
/* ensure mesh validity, then grab data */
if (dm == NULL)
return NULL;
DM_ensure_tessface(dm);
mvert = (dm) ? dm->getVertArray(dm) : NULL;
@@ -279,31 +314,30 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
rbMeshData *mdata;
int i;
/* count triangles */
for (i = 0; i < totface; i++) {
(mface[i].v4) ? (tottris += 2) : (tottris += 1);
}
/* init mesh data for collision shape */
mdata = RB_trimesh_data_new();
mdata = RB_trimesh_data_new(tottris, totvert);
RB_trimesh_add_vertices(mdata, (float*)mvert, totvert, sizeof(MVert));
/* loop over all faces, adding them as triangles to the collision shape
* (so for some faces, more than triangle will get added)
*/
for (i = 0; (i < totface) && (mface) && (mvert); i++, mface++) {
/* add first triangle - verts 1,2,3 */
{
MVert *va = (mface->v1 < totvert) ? (mvert + mface->v1) : (mvert);
MVert *vb = (mface->v2 < totvert) ? (mvert + mface->v2) : (mvert);
MVert *vc = (mface->v3 < totvert) ? (mvert + mface->v3) : (mvert);
RB_trimesh_add_triangle(mdata, va->co, vb->co, vc->co);
}
RB_trimesh_add_triangle_indices(mdata, triangle_index, mface->v1, mface->v2, mface->v3);
triangle_index++;
/* add second triangle if needed - verts 1,3,4 */
if (mface->v4) {
MVert *va = (mface->v1 < totvert) ? (mvert + mface->v1) : (mvert);
MVert *vb = (mface->v3 < totvert) ? (mvert + mface->v3) : (mvert);
MVert *vc = (mface->v4 < totvert) ? (mvert + mface->v4) : (mvert);
RB_trimesh_add_triangle(mdata, va->co, vb->co, vc->co);
RB_trimesh_add_triangle_indices(mdata, triangle_index, mface->v1, mface->v3, mface->v4);
triangle_index++;
}
}
RB_trimesh_finish(mdata);
/* construct collision shape
*
@@ -322,10 +356,86 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
}
}
/* cleanup temp data */
if (dm) {
if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE)
dm->release(dm);
}
else {
printf("ERROR: cannot make Triangular Mesh collision shape for non-Mesh object\n");
}
return shape;
}
/* create collision shape of mesh - convex decomposition
* returns NULL if creation fails.
*/
static rbCollisionShape *rigidbody_get_shape_convex_decomp_from_mesh(Object *ob)
{
rbCollisionShape *shape = NULL;
if (ob->type == OB_MESH) {
DerivedMesh *dm = NULL;
MVert *mvert;
MFace *mface;
int totvert;
int totface;
int tottris = 0;
dm = rigidbody_get_mesh(ob);
/* ensure mesh validity, then grab data */
BLI_assert(dm!= NULL); // RB_TODO need to make sure there's no case where deform derived mesh doesn't exist
DM_ensure_tessface(dm);
mvert = (dm) ? dm->getVertArray(dm) : NULL;
totvert = (dm) ? dm->getNumVerts(dm) : 0;
mface = (dm) ? dm->getTessFaceArray(dm) : NULL;
totface = (dm) ? dm->getNumTessFaces(dm) : 0;
/* sanity checking - potential case when no data will be present */
if ((totvert == 0) || (totface == 0)) {
printf("WARNING: no geometry data converted for Mesh Collision Shape (ob = %s)\n", ob->id.name + 2);
}
else {
rbHACDMeshData *mdata;
int i;
/* count triangles */
for (i = 0; (i < totface) && (mface); i++) {
(mface->v4) ? (tottris += 2) : (tottris += 1);
}
/* init mesh data for collision shape */
mdata = RB_hacd_mesh_new(tottris, totvert);
/* loop over all faces, adding them as triangles to the collision shape
* (so for some faces, more than triangle will get added)
*/
for (i = 0; (i < totface) && (mface) && (mvert); i++, mface++) {
/* add first triangle - verts 1,2,3 */
{
MVert *va = (mface->v1 < totvert) ? (mvert + mface->v1) : (mvert);
MVert *vb = (mface->v2 < totvert) ? (mvert + mface->v2) : (mvert);
MVert *vc = (mface->v3 < totvert) ? (mvert + mface->v3) : (mvert);
RB_hacd_mesh_add_triangle(mdata, va->co, vb->co, vc->co);
}
/* add second triangle if needed - verts 1,3,4 */
if (mface->v4) {
MVert *va = (mface->v1 < totvert) ? (mvert + mface->v1) : (mvert);
MVert *vb = (mface->v3 < totvert) ? (mvert + mface->v3) : (mvert);
MVert *vc = (mface->v4 < totvert) ? (mvert + mface->v4) : (mvert);
RB_hacd_mesh_add_triangle(mdata, va->co, vb->co, vc->co);
}
}
shape = RB_shape_new_convex_decomp(mdata);
}
if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE)
dm->release(dm);
}
else {
printf("ERROR: cannot make Triangular Mesh collision shape for non-Mesh object\n");
@@ -334,15 +444,69 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
return shape;
}
/* check parent child relationships to construct compound shapes */
static void rigidbody_prepare_compounds(RigidBodyWorld *rbw)
{
GroupObject *go;
for (go = rbw->group->gobject.first; go; go = go->next) {
Object *ob = go->ob;
RigidBodyOb *rbo = ob ? ob->rigidbody_object : NULL;
if (rbo == NULL)
continue;
if (ob->parent && ob->parent->rigidbody_object) {
rbo->flag |= RBO_FLAG_COMPOUND_CHILD;
ob->parent->rigidbody_object->flag |= RBO_FLAG_COMPOUND_PARENT;
}
}
}
/* note, object must be a compound shape parent */
static void rigidbody_compound_shape_add_children(RigidBodyWorld *rbw, Object *ob)
{
GroupObject *go;
RigidBodyOb *rbo = ob->rigidbody_object;
if (rbo == NULL)
return;
// RB_TODO check entire parent hirarchy not only one level.
for (go = rbw->group->gobject.first; go; go = go->next) {
Object *child_ob = go->ob;
RigidBodyOb *child_rbo = child_ob ? child_ob->rigidbody_object : NULL;
if (child_rbo && child_rbo->flag & RBO_FLAG_COMPOUND_CHILD) {
if (child_ob->parent == ob) {
float pos[3], orn[4];
mat4_to_loc_quat(pos, orn, child_ob->obmat);
RB_shape_add_compound_child(rbo->physics_object, child_rbo->physics_shape, pos, orn);
}
}
}
}
static void rigidbody_update_compounds(RigidBodyWorld *rbw)
{
GroupObject *go;
for (go = rbw->group->gobject.first; go; go = go->next) {
Object *ob = go->ob;
RigidBodyOb *rbo = ob ? ob->rigidbody_object : NULL;
if (rbo && rbo->flag & RBO_FLAG_COMPOUND_PARENT)
rigidbody_compound_shape_add_children(rbw, ob);
}
}
/* Create new physics sim collision shape for object and store it,
* or remove the existing one first and replace...
*/
void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
{
RigidBodyOb *rbo = ob->rigidbody_object;
rbCollisionShape *new_shape = NULL;
BoundBox *bb = NULL;
float size[3] = {1.0f, 1.0f, 1.0f};
float center[3], min[3], max[3];
float loc[3], rot[4];
float radius = 1.0f;
float height = 1.0f;
float capsule_height;
@@ -383,25 +547,33 @@ void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
radius = MAX3(size[0], size[1], size[2]);
}
mat4_to_loc_quat(loc, rot, ob->obmat);
/* calculate world space center of object */
mul_v3_m4v3(min, ob->obmat, bb->vec[0]);
mul_v3_m4v3(max, ob->obmat, bb->vec[6]);
add_v3_v3v3(center, max, min);
mul_v3_fl(center, 0.5f);
/* create new shape */
switch (rbo->shape) {
case RB_SHAPE_BOX:
new_shape = RB_shape_new_box(size[0], size[1], size[2]);
new_shape = RB_shape_new_box(size[0], size[1], size[2], loc, rot, center);
break;
case RB_SHAPE_SPHERE:
new_shape = RB_shape_new_sphere(radius);
new_shape = RB_shape_new_sphere(radius, loc, rot, center);
break;
case RB_SHAPE_CAPSULE:
capsule_height = (height - radius) * 2.0f;
new_shape = RB_shape_new_capsule(radius, (capsule_height > 0.0f) ? capsule_height : 0.0f);
new_shape = RB_shape_new_capsule(radius, (capsule_height > 0.0f) ? capsule_height : 0.0f, loc, rot, center);
break;
case RB_SHAPE_CYLINDER:
new_shape = RB_shape_new_cylinder(radius, height);
new_shape = RB_shape_new_cylinder(radius, height, loc, rot, center);
break;
case RB_SHAPE_CONE:
new_shape = RB_shape_new_cone(radius, height * 2.0f);
new_shape = RB_shape_new_cone(radius, height * 2.0f, loc, rot, center);
break;
case RB_SHAPE_CONVEXH:
@@ -417,6 +589,9 @@ void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
case RB_SHAPE_TRIMESH:
new_shape = rigidbody_get_shape_trimesh_from_mesh(ob);
break;
case RB_SHAPE_APPROX:
new_shape = rigidbody_get_shape_convex_decomp_from_mesh(ob);
break;
}
/* assign new collision shape if creation was successful */
if (new_shape) {
@@ -425,9 +600,10 @@ void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
rbo->physics_shape = new_shape;
RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo));
}
else { /* otherwise fall back to box shape */
/* use box shape if we can't fall back to old shape */
else if (rbo->physics_shape == NULL) {
rbo->shape = RB_SHAPE_BOX;
BKE_rigidbody_validate_sim_shape(ob, true);
rigidbody_validate_sim_shape(ob, true);
}
}
@@ -436,7 +612,7 @@ void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
/* Create physics sim representation of object given RigidBody settings
* < rebuild: even if an instance already exists, replace it
*/
void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short rebuild)
static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool rebuild)
{
RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL;
float loc[3];
@@ -451,11 +627,10 @@ void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short re
/* make sure collision shape exists */
/* FIXME we shouldn't always have to rebuild collision shapes when rebuilding objects, but it's needed for constraints to update correctly */
if (rbo->physics_shape == NULL || rebuild)
BKE_rigidbody_validate_sim_shape(ob, true);
rigidbody_validate_sim_shape(ob, true);
if (rbo->physics_object) {
if (rebuild == false)
RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
if (rbo->physics_object && rebuild == false) {
RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
}
if (!rbo->physics_object || rebuild) {
/* remove rigid body if it already exists before creating a new one */
@@ -474,7 +649,7 @@ void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short re
RB_body_set_sleep_thresh(rbo->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh);
RB_body_set_activation_state(rbo->physics_object, rbo->flag & RBO_FLAG_USE_DEACTIVATION);
if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_START_DEACTIVATED)
if (rbo->type == RBO_TYPE_PASSIVE)
RB_body_deactivate(rbo->physics_object);
@@ -488,10 +663,17 @@ void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short re
(ob->protectflag & OB_LOCK_ROTZ) == 0);
RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
if (rbo->flag & RBO_FLAG_START_DEACTIVATED)
RB_body_suspend(rbo->physics_object);
RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
RB_body_set_trigger(rbo->physics_object, rbo->flag & RBO_FLAG_TRIGGER);
RB_body_set_ghost(rbo->physics_object, rbo->flag & RBO_FLAG_GHOST);
RB_body_set_activation_type(rbo->physics_object, rbo->activation_type);
RB_body_set_activation_time(rbo->physics_object, rbo->activation_time);
RB_body_set_activation_impulse(rbo->physics_object, rbo->activation_impulse);
}
if (rbw && rbw->physics_world)
if (rbw && rbw->physics_world && (rbo->flag & RBO_FLAG_COMPOUND_CHILD) == 0) // RB_TODO find better solution for compound shapes
RB_dworld_add_body(rbw->physics_world, rbo->physics_object, rbo->col_groups);
}
@@ -500,7 +682,7 @@ void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short re
/* Create physics sim representation of constraint given rigid body constraint settings
* < rebuild: even if an instance already exists, replace it
*/
void BKE_rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, short rebuild)
static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, bool rebuild)
{
RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
float loc[3];
@@ -672,7 +854,7 @@ void BKE_rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, shor
/* Create physics sim world given RigidBody world settings */
// NOTE: this does NOT update object references that the scene uses, in case those aren't ready yet!
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, short rebuild)
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
/* sanity checks */
if (rbw == NULL)
@@ -772,6 +954,8 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
/* create new settings data, and link it up */
rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb");
rbo->effector_weights = BKE_add_effector_weights(NULL);
/* set default settings */
rbo->type = type;
@@ -790,6 +974,8 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
rbo->col_groups = 1;
rbo->activation_time = 1.0f;
/* use triangle meshes for passive objects
* use convex hulls for active objects since dynamic triangle meshes are very unstable
*/
@@ -797,6 +983,8 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
rbo->shape = RB_SHAPE_CONVEXH;
else
rbo->shape = RB_SHAPE_TRIMESH;
rbo->mesh_source = RBO_MESH_DEFORM;
/* set initial transform */
mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat);
@@ -1000,6 +1188,20 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
if (rbo->physics_object == NULL)
return;
if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) {
DerivedMesh *dm = ob->derivedDeform;
if (dm) {
MVert *mvert = dm->getVertArray(dm);
int totvert = dm->getNumVerts(dm);
BoundBox *bb = BKE_object_boundbox_get(ob);
RB_shape_trimesh_update(rbo->physics_shape, (float*)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]);
}
}
if (rbo->type == RBO_TYPE_ACTIVE && rbo->activation_type == RBO_ACTIVATION_TIME)
RB_body_try_activation(rbo->physics_object);
mat4_decompose(loc, rot, scale, ob->obmat);
/* update scale for all objects */
@@ -1022,13 +1224,16 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
/* update influence of effectors - but don't do it on an effector */
/* only dynamic bodies need effector update */
else if (rbo->type == RBO_TYPE_ACTIVE && ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
EffectorWeights *effector_weights = rbw->effector_weights;
EffectedPoint epoint;
ListBase *effectors;
ListBase *effectors_local;
ListBase *effectors_global;
/* get effectors present in the group specified by effector_weights */
effectors = pdInitEffectors(scene, ob, NULL, effector_weights);
if (effectors) {
effectors_local = pdInitEffectors(scene, ob, NULL, rbo->effector_weights);
effectors_global = pdInitEffectors(scene, ob, NULL, rbw->effector_weights);
if (effectors_local && effectors_global) {
float eff_force_local[3] = {0.0f, 0.0f, 0.0f};
float eff_force_global[3] = {0.0f, 0.0f, 0.0f};
float eff_force[3] = {0.0f, 0.0f, 0.0f};
float eff_loc[3], eff_vel[3];
@@ -1042,19 +1247,22 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
/* calculate net force of effectors, and apply to sim object
* - we use 'central force' since apply force requires a "relative position" which we don't have...
*/
pdDoEffectors(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
if (G.f & G_DEBUG)
printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2);
pdDoEffectors(effectors_local, NULL, rbo->effector_weights, &epoint, eff_force_local, NULL);
pdDoEffectors(effectors_global, NULL, rbw->effector_weights, &epoint, eff_force_global, NULL);
add_v3_v3v3(eff_force, eff_force_global, eff_force_local);
mul_v3_fl(eff_force, 0.5f);
/* activate object in case it is deactivated */
if (!is_zero_v3(eff_force))
if (!is_zero_v3(eff_force)) {
/* adjust the force based on fps, use 24 as neutral point since it's blender's default */
mul_v3_fl(eff_force, (float)FPS / 24.0f);
RB_body_activate(rbo->physics_object);
RB_body_apply_central_force(rbo->physics_object, eff_force);
RB_body_apply_central_force(rbo->physics_object, eff_force);
}
}
else if (G.f & G_DEBUG)
printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
/* cleanup */
pdEndEffectors(&effectors);
pdEndEffectors(&effectors_global);
pdEndEffectors(&effectors_local);
}
/* NOTE: passive objects don't need to be updated since they don't move */
@@ -1066,7 +1274,7 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
/* Updates and validates world, bodies and shapes.
* < rebuild: rebuild entire simulation
*/
static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int rebuild)
static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
GroupObject *go;
@@ -1074,8 +1282,11 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
if (rebuild)
BKE_rigidbody_validate_sim_world(scene, rbw, true);
rigidbody_update_sim_world(scene, rbw);
/* update objects */
if (rebuild)
rigidbody_prepare_compounds(rbw);
for (go = rbw->group->gobject.first; go; go = go->next) {
Object *ob = go->ob;
@@ -1091,7 +1302,7 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
* - assume object to be active? That is the default for newly added settings...
*/
ob->rigidbody_object = BKE_rigidbody_create_object(scene, ob, RBO_TYPE_ACTIVE);
BKE_rigidbody_validate_sim_object(rbw, ob, true);
rigidbody_validate_sim_object(rbw, ob, true);
rbo = ob->rigidbody_object;
}
@@ -1100,15 +1311,15 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
/* refresh object... */
if (rebuild) {
/* World has been rebuilt so rebuild object */
BKE_rigidbody_validate_sim_object(rbw, ob, true);
rigidbody_validate_sim_object(rbw, ob, true);
}
else if (rbo->flag & RBO_FLAG_NEEDS_VALIDATE) {
BKE_rigidbody_validate_sim_object(rbw, ob, false);
rigidbody_validate_sim_object(rbw, ob, false);
}
/* refresh shape... */
if (rbo->flag & RBO_FLAG_NEEDS_RESHAPE) {
/* mesh/shape data changed, so force shape refresh */
BKE_rigidbody_validate_sim_shape(ob, true);
rigidbody_validate_sim_shape(ob, true);
/* now tell RB sim about it */
// XXX: we assume that this can only get applied for active/passive shapes that will be included as rigidbodies
RB_body_set_collision_shape(rbo->physics_object, rbo->physics_shape);
@@ -1120,6 +1331,10 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
rigidbody_update_sim_ob(scene, rbw, ob, rbo);
}
}
if (rebuild)
rigidbody_update_compounds(rbw);
/* update constraints */
if (rbw->constraints == NULL) /* no constraints, move on */
return;
@@ -1137,7 +1352,7 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
* constraint settings (perhaps it was added manually), add!
*/
ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
BKE_rigidbody_validate_sim_constraint(rbw, ob, true);
rigidbody_validate_sim_constraint(rbw, ob, true);
rbc = ob->rigidbody_constraint;
}
@@ -1145,10 +1360,10 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
/* perform simulation data updates as tagged */
if (rebuild) {
/* World has been rebuilt so rebuild constraint */
BKE_rigidbody_validate_sim_constraint(rbw, ob, true);
rigidbody_validate_sim_constraint(rbw, ob, true);
}
else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
BKE_rigidbody_validate_sim_constraint(rbw, ob, false);
rigidbody_validate_sim_constraint(rbw, ob, false);
}
rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
}

View File

@@ -4954,6 +4954,12 @@ static void direct_link_object(FileData *fd, Object *ob)
if (ob->rigidbody_object) {
RigidBodyOb *rbo = ob->rigidbody_object;
rbo->effector_weights = newdataadr(fd, rbo->effector_weights);
if (rbo->effector_weights)
rbo->effector_weights->group = newlibadr(fd, ob->id.lib, rbo->effector_weights->group);
else
rbo->effector_weights = BKE_add_effector_weights(NULL);
/* must nullify the references to physics sim objects, since they no-longer exist
* (and will need to be recalculated)
*/

View File

@@ -1525,6 +1525,7 @@ static void write_objects(WriteData *wd, ListBase *idbase)
if (ob->rigidbody_object) {
// TODO: if any extra data is added to handle duplis, will need separate function then
writestruct(wd, DATA, "RigidBodyOb", 1, ob->rigidbody_object);
writestruct(wd, DATA, "EffectorWeights", 1, ob->rigidbody_object->effector_weights);
}
if (ob->rigidbody_constraint) {
writestruct(wd, DATA, "RigidBodyCon", 1, ob->rigidbody_constraint);

View File

@@ -347,6 +347,7 @@ static int rigidbody_objects_shape_change_exec(bContext *C, wmOperator *op)
if (change) {
/* send updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
/* done */
return OPERATOR_FINISHED;
@@ -535,6 +536,7 @@ static float rigidbody_object_calc_volume(Object *ob)
*/
case RB_SHAPE_CONVEXH:
case RB_SHAPE_TRIMESH:
case RB_SHAPE_APPROX:
volume = size[0] * size[1] * size[2];
break;

View File

@@ -6203,7 +6203,7 @@ static void get_local_bounds(Object *ob, float center[3], float size[3])
}
#endif
static void draw_bb_quadric(BoundBox *bb, char type)
static void draw_bb_quadric(BoundBox *bb, char type, float *offset)
{
float size[3], cent[3];
GLUquadricObj *qobj = gluNewQuadric();
@@ -6219,6 +6219,8 @@ static void draw_bb_quadric(BoundBox *bb, char type)
cent[2] = 0.5f * (bb->vec[0][2] + bb->vec[1][2]);
glPushMatrix();
if (offset)
glTranslatef(offset[0], offset[1], offset[2]);
if (type == OB_BOUND_SPHERE) {
float scale = MAX3(size[0], size[1], size[2]);
glTranslatef(cent[0], cent[1], cent[2]);
@@ -6280,11 +6282,41 @@ static void draw_bounding_volume(Scene *scene, Object *ob, char type)
BKE_boundbox_init_from_minmax(bb, min, max);
}
if (bb == NULL) return;
if (type == OB_BOUND_BOX) draw_box(bb->vec);
else draw_bb_quadric(bb, type);
if (bb == NULL)
return;
if (ob->gameflag & OB_BOUNDS) { /* need to offset bounds for game engine, so it's drawn around origin */
float offset[3], center[3], min[3], max[3];
mul_v3_m4v3(min, ob->obmat, bb->vec[0]);
mul_v3_m4v3(max, ob->obmat, bb->vec[6]);
add_v3_v3v3(center, max, min);
mul_v3_fl(center, 0.5f);
sub_v3_v3v3(offset, ob->obmat[3], center);
if (type == OB_BOUND_BOX) {
float vec[8][3];
add_v3_v3v3(vec[0], bb->vec[0], offset);
add_v3_v3v3(vec[1], bb->vec[1], offset);
add_v3_v3v3(vec[2], bb->vec[2], offset);
add_v3_v3v3(vec[3], bb->vec[3], offset);
add_v3_v3v3(vec[4], bb->vec[4], offset);
add_v3_v3v3(vec[5], bb->vec[5], offset);
add_v3_v3v3(vec[6], bb->vec[6], offset);
add_v3_v3v3(vec[7], bb->vec[7], offset);
draw_box(vec);
}
else {
draw_bb_quadric(bb, type, offset);
}
}
else {
if (type == OB_BOUND_BOX)
draw_box(bb->vec);
else
draw_bb_quadric(bb, type, NULL);
}
}
static void drawtexspace(Object *ob)
@@ -6567,6 +6599,36 @@ static void draw_object_matcap_check(Scene *scene, View3D *v3d, Object *ob)
}
static void draw_rigidbody_shape(Object *ob)
{
BoundBox *bb = NULL;
if (ob->type == OB_MESH) {
bb = BKE_mesh_boundbox_get(ob);
}
if (bb == NULL)
return;
switch (ob->rigidbody_object->shape) {
case RB_SHAPE_BOX:
draw_box(bb->vec);
break;
case RB_SHAPE_SPHERE:
draw_bb_quadric(bb, OB_BOUND_SPHERE, NULL);
break;
case RB_SHAPE_CONE:
draw_bb_quadric(bb, OB_BOUND_CONE, NULL);
break;
case RB_SHAPE_CYLINDER:
draw_bb_quadric(bb, OB_BOUND_CYLINDER, NULL);
break;
case RB_SHAPE_CAPSULE:
draw_bb_quadric(bb, OB_BOUND_CAPSULE, NULL);
break;
}
}
/**
* main object drawing function, draws in selection
* \param dflag (draw flag) can be DRAW_PICKING and/or DRAW_CONSTCOLOR, DRAW_SCENESET
@@ -6709,6 +6771,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
/* draw-extra supported for boundbox drawmode too */
if (dt >= OB_BOUNDBOX) {
dtx = ob->dtx;
if (ob->mode & OB_MODE_EDIT) {
// the only 2 extra drawtypes alowed in editmode
@@ -7114,21 +7177,26 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
if (!render_override) {
bConstraint *con;
if ((v3d->flag2 & V3D_NO_PHYSICS) == 0) {
bConstraint *con;
for (con = ob->constraints.first; con; con = con->next) {
if (con->type == CONSTRAINT_TYPE_RIGIDBODYJOINT) {
bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint *)con->data;
if (data->flag & CONSTRAINT_DRAW_PIVOT)
draw_rigid_body_pivot(data, dflag, ob_wire_col);
for (con = ob->constraints.first; con; con = con->next) {
if (con->type == CONSTRAINT_TYPE_RIGIDBODYJOINT) {
bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint *)con->data;
if (data->flag & CONSTRAINT_DRAW_PIVOT)
draw_rigid_body_pivot(data, dflag, ob_wire_col);
}
}
}
if ((ob->gameflag & OB_BOUNDS) && (ob->mode == OB_MODE_OBJECT)) {
if (ob->boundtype != ob->collision_boundtype || (dtx & OB_DRAWBOUNDOX) == 0) {
setlinestyle(2);
draw_bounding_volume(scene, ob, ob->collision_boundtype);
setlinestyle(0);
if (ob->gameflag & OB_BOUNDS) {
if (ob->boundtype != ob->collision_boundtype || (dtx & OB_DRAWBOUNDOX) == 0) {
setlinestyle(2);
draw_bounding_volume(scene, ob, ob->collision_boundtype);
setlinestyle(0);
}
}
if (ob->rigidbody_object) {
draw_rigidbody_shape(ob);
}
}

View File

@@ -3334,6 +3334,9 @@ static void view3d_main_area_draw_objects(const bContext *C, ARegion *ar, const
draw_object(scene, ar, v3d, base, 0);
}
}
// HACK draw bullet debug world
GPU_debug_draw();
// REEB_draw();

View File

@@ -45,6 +45,17 @@ struct View3D;
struct RegionView3D;
struct SmokeModifierData;
// HACK bullet debug draw functions
typedef struct GPUDebugVert {
float pos[3];
float col[3];
} GPUDebugVert;
void GPU_debug_add_line(float p1[3], float p2[3], float col[3]);
void GPU_debug_add_point(float pos[3], float col[3]);
void GPU_debug_draw(void);
void GPU_debug_reset(void);
/* OpenGL drawing functions related to shading. These are also
* shared with the game engine, where there were previously
* duplicates of some of these functions. */

View File

@@ -74,6 +74,11 @@
extern Material defmaterial; /* from material.c */
static GPUDebugVert GPU_varr[100000];
static int GPU_varr_numverts = 0;
static GPUDebugVert GPU_parr[100000];
static int GPU_parr_numverts = 0;
/* These are some obscure rendering functions shared between the
* game engine and the blender, in this module to avoid duplicaten
* and abstract them away from the rest a bit */
@@ -87,6 +92,57 @@ static void gpu_mcol(unsigned int ucol)
glColor3ub(cp[3], cp[2], cp[1]);
}
// HACK bullet debug draw functions
void GPU_debug_add_line(float p1[3], float p2[3], float col[3])
{
if (G.debug_value == 616) {
copy_v3_v3(GPU_varr[GPU_varr_numverts].pos, p1);
copy_v3_v3(GPU_varr[GPU_varr_numverts].col, col);
GPU_varr_numverts++;
copy_v3_v3(GPU_varr[GPU_varr_numverts].pos, p2);
copy_v3_v3(GPU_varr[GPU_varr_numverts].col, col);
GPU_varr_numverts++;
}
}
void GPU_debug_add_point(float pos[3], float col[3])
{
if (G.debug_value == 616) {
copy_v3_v3(GPU_parr[GPU_parr_numverts].pos, pos);
copy_v3_v3(GPU_parr[GPU_parr_numverts].col, col);
GPU_parr_numverts++;
}
}
void GPU_debug_draw(void)
{
if (G.debug_value == 616) {
// glDisable(GL_DEPTH_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(GPUDebugVert), GPU_varr);
glColorPointer(3, GL_FLOAT, sizeof(GPUDebugVert), &(GPU_varr->col[0]));
glDrawArrays(GL_LINES, 0, GPU_varr_numverts);
glDisable(GL_DEPTH_TEST);
glPointSize(5.0f);
glVertexPointer(3, GL_FLOAT, sizeof(GPUDebugVert), GPU_parr);
glColorPointer(3, GL_FLOAT, sizeof(GPUDebugVert), &(GPU_parr->col[0]));
glDrawArrays(GL_POINTS, 0, GPU_parr_numverts);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glEnable(GL_DEPTH_TEST);
}
}
void GPU_debug_reset(void)
{
GPU_varr_numverts = 0;
GPU_parr_numverts = 0;
}
void GPU_render_text(MTFace *tface, int mode,
const char *textstr, int textlen, unsigned int *col,
float *v1, float *v2, float *v3, float *v4, int glattrib)

View File

@@ -103,7 +103,8 @@ typedef struct RigidBodyOb {
int flag; /* (eRigidBodyOb_Flag) */
int col_groups; /* Collision groups that determines wich rigid bodies can collide with each other */
int pad;
short mesh_source; /* (eRigidBody_MeshSource) mesh source for mesh based collision shapes */
short activation_type; /* (eRigidBody_ActivationType) specifies how the RigidBody can be activaged */
/* Physics Parameters */
float mass; /* how much object 'weighs' (i.e. absolute 'amount of stuff' it holds) */
@@ -121,7 +122,10 @@ typedef struct RigidBodyOb {
float orn[4]; /* rigid body orientation */
float pos[3]; /* rigid body position */
float pad1;
float activation_time; /* time until body is activated */
float activation_impulse; /* impulse threshold that needs to be reached for body to get activated */
int pad;
struct EffectorWeights *effector_weights;
} RigidBodyOb;
@@ -148,7 +152,16 @@ typedef enum eRigidBodyOb_Flag {
/* rigidbody is not dynamically simulated */
RBO_FLAG_DISABLED = (1 << 5),
/* collision margin is not embedded (only used by convex hull shapes for now) */
RBO_FLAG_USE_MARGIN = (1 << 6)
RBO_FLAG_USE_MARGIN = (1 << 6),
/* compound shape flags, should not be set manually */
RBO_FLAG_COMPOUND_PARENT = (1 << 7),
RBO_FLAG_COMPOUND_CHILD = (1 << 8),
/* rigidbdody is used as a collision trigger */
RBO_FLAG_TRIGGER = (1 << 9),
/* rigidbdody has no collision response */
RBO_FLAG_GHOST = (1 << 10),
/* collision shape deforms during simulation (only for passive triangle mesh shapes) */
RBO_FLAG_USE_DEFORM = (1 << 11)
} eRigidBodyOb_Flag;
/* RigidBody Collision Shape */
@@ -168,11 +181,28 @@ typedef enum eRigidBody_Shape {
RB_SHAPE_CONVEXH,
/* triangulated mesh */
RB_SHAPE_TRIMESH,
/* concave mesh approximated using primitives */
//RB_SHAPE_COMPOUND,
/* concave mesh approximated using convex hulls */
RB_SHAPE_APPROX
} eRigidBody_Shape;
typedef enum eRigidBody_MeshSource {
/* base mesh */
RBO_MESH_BASE = 0,
/* only deformations */
RBO_MESH_DEFORM,
/* final derived mesh */
RBO_MESH_FINAL
} eRigidBody_MeshSource;
typedef enum eRigidBody_ActivationType {
/* body gets activated on collision with other bodies */
RBO_ACTIVATION_COLLISION = 0,
/* body gets activated on collision with a trigger body */
RBO_ACTIVATION_TRIGGER,
/* body gets activated after a certain ammount of time */
RBO_ACTIVATION_TIME
} eRigidBody_ActivationType;
/* ******************************** */
/* RigidBody Constraint */

View File

@@ -281,6 +281,7 @@ typedef struct View3D {
#define V3D_SHOW_SOLID_MATCAP 8192 /* runtime flag */
#define V3D_OCCLUDE_WIRE 16384
#define V3D_SHADELESS_TEX 32768
#define V3D_NO_PHYSICS 32768 // RB_FIXME need new drawing flag
/* View3D->around */

View File

@@ -61,6 +61,8 @@ EnumPropertyItem rigidbody_object_shape_items[] = {
"fewer vertices)"},
{RB_SHAPE_TRIMESH, "MESH", ICON_MESH_MONKEY, "Mesh",
"Mesh consisting of triangles only, allowing for more detailed interactions than convex hulls"},
{RB_SHAPE_APPROX, "APPROX", ICON_MESH_MONKEY, "Approx",
"Approximation of the mesh using convex decomposition"},
{0, NULL, 0, NULL, NULL}};
/* collision shapes of constraints in rigid body sim */
@@ -76,6 +78,19 @@ EnumPropertyItem rigidbody_constraint_type_items[] = {
{RBC_TYPE_MOTOR, "MOTOR", ICON_NONE, "Motor", "Drive rigid body around or along an axis"},
{0, NULL, 0, NULL, NULL}};
/* mesh source for collision shape creation */
EnumPropertyItem rigidbody_mesh_source_items[] = {
{RBO_MESH_BASE, "BASE", 0, "Base", "Base mesh"},
{RBO_MESH_DEFORM, "DEFORM", 0, "Deform", "Deformations (shaps keys, deform modifiers"},
{RBO_MESH_FINAL, "FINAL", 0, "Final", "All modifiers"},
{0, NULL, 0, NULL, NULL}};
EnumPropertyItem rigidbody_activation_type_items[] = {
{RBO_ACTIVATION_COLLISION, "COLLISION", 0, "Collision", "Activation on collision with other rigid bodies"},
{RBO_ACTIVATION_TRIGGER, "TRIGGER", 0, "Trigger", "Activation on collision with trigger object"},
{RBO_ACTIVATION_TIME, "TIME", 0, "Time", "Activation after a specified ammount of time"},
{0, NULL, 0, NULL, NULL}};
#ifdef RNA_RUNTIME
@@ -768,7 +783,21 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Type", "Role of object in Rigid Body Simulations");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
prop = RNA_def_property(srna, "mesh_source", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mesh_source");
RNA_def_property_enum_items(prop, rigidbody_mesh_source_items);
RNA_def_property_ui_text(prop, "Mesh Source", "Source of the mesh used to create collision shape");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
prop = RNA_def_property(srna, "activation_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "activation_type");
RNA_def_property_enum_items(prop, rigidbody_activation_type_items);
RNA_def_property_ui_text(prop, "Activation Type", "Type of activation used");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
/* booleans */
prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", RBO_FLAG_DISABLED);
@@ -782,7 +811,7 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
RNA_def_property_enum_funcs(prop, NULL, "rna_RigidBodyOb_shape_set", NULL);
RNA_def_property_ui_text(prop, "Collision Shape", "Collision Shape of object in Rigid Body Simulations");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_RigidBodyOb_reset");
prop = RNA_def_property(srna, "kinematic", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_KINEMATIC);
@@ -790,6 +819,23 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Kinematic", "Allow rigid body to be controlled by the animation system");
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
prop = RNA_def_property(srna, "trigger", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_TRIGGER);
RNA_def_property_ui_text(prop, "Trigger", "Rigid body acts as collision trigger");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_GHOST);
RNA_def_property_ui_text(prop, "Ghost", "Rigid body does not respond to collisions");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
prop = RNA_def_property(srna, "use_deform", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_USE_DEFORM);
RNA_def_property_ui_text(prop, "Deforming", "Rigid body deforms during simulation");
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
/* Physics Parameters */
prop = RNA_def_property(srna, "mass", PROP_FLOAT, PROP_UNIT_MASS);
RNA_def_property_float_sdna(prop, NULL, "mass");
@@ -800,15 +846,29 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
/* Dynamics Parameters - Activation */
// TODO: define and figure out how to implement these
prop = RNA_def_property(srna, "activation_time", PROP_FLOAT, PROP_UNIT_TIME);
RNA_def_property_float_sdna(prop, NULL, "activation_time");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Time", "Time until activation");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
prop = RNA_def_property(srna, "activation_impulse", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "activation_impulse");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_ui_text(prop, "Impulse Threshold", "Impulse that need to be reached for body to be activated");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
/* Dynamics Parameters - Deactivation */
prop = RNA_def_property(srna, "use_deactivation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_USE_DEACTIVATION);
RNA_def_property_boolean_default(prop, TRUE);
RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyOb_activation_state_set");
RNA_def_property_ui_text(prop, "Enable Deactivation",
"Enable deactivation of resting rigid bodies (increases performance and stability "
RNA_def_property_ui_text(prop, "Allow Deactivation",
"Allow deactivation of resting rigid bodies (increases performance and stability "
"but can cause glitches)");
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
@@ -900,6 +960,12 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Collision Groups", "Collision Groups Rigid Body belongs to");
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
/* effector weights */
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "EffectorWeights");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Effector Weights", "");
}
static void rna_def_rigidbody_constraint(BlenderRNA *brna)

View File

@@ -1971,6 +1971,11 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Only Render", "Display only objects which will be rendered");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "show_physics", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag2", V3D_NO_PHYSICS);
RNA_def_property_ui_text(prop, "Physics", "Display physics visualization");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
prop = RNA_def_property(srna, "use_occlude_geometry", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_ZBUF_SELECT);
RNA_def_property_ui_text(prop, "Occlude Geometry", "Limit selection to visible (clipped with depth buffer)");

View File

@@ -121,6 +121,7 @@ endif()
ge_logic_network
ge_logic_ngnetwork
ge_logic_loopbacknetwork
extern_hacd
extern_bullet
bf_intern_guardedalloc
bf_intern_memutil

View File

@@ -1063,6 +1063,7 @@ endif()
if(WITH_BULLET)
list_insert_after(BLENDER_SORTED_LIBS "bf_blenkernel" "bf_intern_rigidbody")
list_insert_after(BLENDER_SORTED_LIBS "bf_intern_rigidbody" "extern_hacd")
endif()
if(WITH_BULLET AND NOT WITH_SYSTEM_BULLET)