[Bf-blender-cvs] [9ba5c8b90aa] soc-2020-soft-body: first commit. interfaced to very basic admmpd solver, but requires restart to begin sim as caching not working for velocity. lattice is simply a packed 5-tet cube around mesh.

over0219 noreply at git.blender.org
Wed Jun 3 06:26:45 CEST 2020


Commit: 9ba5c8b90aa6245c569f7e66b0cd472beb59b5a5
Author: over0219
Date:   Tue Jun 2 19:53:14 2020 -0500
Branches: soc-2020-soft-body
https://developer.blender.org/rB9ba5c8b90aa6245c569f7e66b0cd472beb59b5a5

first commit. interfaced to very basic admmpd solver, but requires restart to begin sim as caching not working for velocity. lattice is simply a packed 5-tet cube around mesh.

===================================================================

M	extern/CMakeLists.txt
A	extern/softbody/CMakeLists.txt
A	extern/softbody/README.md
A	extern/softbody/src/admmpd_energy.cpp
A	extern/softbody/src/admmpd_energy.h
A	extern/softbody/src/admmpd_lattice.cpp
A	extern/softbody/src/admmpd_lattice.h
A	extern/softbody/src/admmpd_math.cpp
A	extern/softbody/src/admmpd_math.h
A	extern/softbody/src/admmpd_solver.cpp
A	extern/softbody/src/admmpd_solver.h
M	intern/CMakeLists.txt
A	intern/softbody/CMakeLists.txt
A	intern/softbody/admmpd_api.cpp
A	intern/softbody/admmpd_api.h
M	release/datafiles/locale
M	release/scripts/addons
M	source/blender/blenkernel/CMakeLists.txt
M	source/blender/blenkernel/intern/softbody.c
M	source/blender/makesdna/DNA_object_force_types.h
M	source/blender/modifiers/intern/MOD_softbody.c
M	source/tools

===================================================================

diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt
index 235c2fa931a..7d4023cf52a 100644
--- a/extern/CMakeLists.txt
+++ b/extern/CMakeLists.txt
@@ -34,6 +34,7 @@ endif()
 
 add_subdirectory(rangetree)
 add_subdirectory(wcwidth)
+add_subdirectory(softbody)
 
 if(WITH_BULLET)
   if(NOT WITH_SYSTEM_BULLET)
diff --git a/extern/softbody/CMakeLists.txt b/extern/softbody/CMakeLists.txt
new file mode 100644
index 00000000000..08a36882f28
--- /dev/null
+++ b/extern/softbody/CMakeLists.txt
@@ -0,0 +1,43 @@
+# ***** 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.
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+  src
+)
+
+set(INC_SYS
+  ${EIGEN3_INCLUDE_DIRS}
+)
+
+set(SRC
+  src/admmpd_math.h
+  src/admmpd_math.cpp
+  src/admmpd_energy.h
+  src/admmpd_energy.cpp
+  src/admmpd_lattice.h
+  src/admmpd_lattice.cpp
+  src/admmpd_solver.h
+  src/admmpd_solver.cpp
+)
+
+set(LIB
+)
+
+blender_add_lib(extern_admmpd "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/extern/softbody/README.md b/extern/softbody/README.md
new file mode 100644
index 00000000000..78144e7b666
--- /dev/null
+++ b/extern/softbody/README.md
@@ -0,0 +1,3 @@
+# SoftBody #
+
+
diff --git a/extern/softbody/src/admmpd_energy.cpp b/extern/softbody/src/admmpd_energy.cpp
new file mode 100644
index 00000000000..978fd565aa4
--- /dev/null
+++ b/extern/softbody/src/admmpd_energy.cpp
@@ -0,0 +1,112 @@
+
+
+
+#include "admmpd_energy.h"
+
+namespace admmpd {
+using namespace Eigen;
+
+Lame::Lame() : m_model(0)
+{
+	set_from_youngs_poisson(10000000,0.299);
+}
+
+void Lame::set_from_youngs_poisson(double youngs, double poisson)
+{
+	m_mu = youngs/(2.0*(1.0+poisson));
+	m_lambda = youngs*poisson/((1.0+poisson)*(1.0-2.0*poisson));
+	m_bulk_mod = m_lambda + (2.0/3.0)*m_mu;
+}
+
+void EnergyTerm::signed_svd(
+	const Eigen::Matrix<double,3,3>& A, 
+	Eigen::Matrix<double,3,3> &U, 
+	Eigen::Matrix<double,3,1> &S, 
+	Eigen::Matrix<double,3,3> &V)
+{
+	JacobiSVD<Matrix3d> svd(A, ComputeFullU | ComputeFullV);
+	S = svd.singularValues();
+	U = svd.matrixU();
+	V = svd.matrixV();
+	Matrix3d J = Matrix3d::Identity();
+	J(2,2) = -1.0;
+	if( U.determinant() < 0.0 )
+	{
+		U = U * J;
+		S[2] = -S[2];
+	}
+	if( V.determinant() < 0.0 )
+	{
+		Matrix3d Vt = V.transpose();
+		Vt = J * Vt;
+		V = Vt.transpose();
+		S[2] = -S[2];
+	}
+}
+
+void EnergyTerm::update(
+	int index,
+	const Lame &lame,
+	double rest_volume,
+	double weight,
+	const Eigen::MatrixXd *x,
+	const Eigen::MatrixXd *Dx,
+	Eigen::MatrixXd *z,
+	Eigen::MatrixXd *u)
+{
+	Matrix3d Dix = Dx->block<3,3>(index,0);
+	Matrix3d ui = u->block<3,3>(index,0);
+	Matrix3d zi = Dix + ui;
+
+	Matrix3d U, V;
+	Vector3d S;
+	signed_svd(zi, U, S, V);
+	S = Vector3d::Ones();
+
+	Matrix3d p = U * S.asDiagonal() * V.transpose();
+	double k = lame.m_bulk_mod;
+	double kv = k * rest_volume;
+	double w2 = weight*weight;
+	zi = (kv*p + w2*zi) / (w2 + kv);
+	ui += (Dix - zi);
+
+	u->block<3,3>(index,0) = ui;
+	z->block<3,3>(index,0) = zi;
+
+} // end EnergyTerm::update
+
+int EnergyTerm::init_tet(
+	int index,
+	const Lame &lame,
+	const Eigen::Matrix<int,1,4> &prim,
+	const Eigen::MatrixXd *x,
+	double &volume,
+	double &weight,
+	std::vector< Eigen::Triplet<double> > &triplets )
+{
+	Matrix<double,3,3> edges;
+	edges.col(0) = x->row(prim[1]) - x->row(prim[0]);
+	edges.col(1) = x->row(prim[2]) - x->row(prim[0]);
+	edges.col(2) = x->row(prim[3]) - x->row(prim[0]);
+	Matrix<double,3,3> edges_inv = edges.inverse();
+	volume = edges.determinant() / 6.0f;
+	if( volume < 0 )
+		throw std::runtime_error("**Solver::energy_init: Inverted initial tet");
+	double k = lame.m_bulk_mod;
+	weight = std::sqrt(k*volume);
+	Matrix<double,4,3> S = Matrix<double,4,3>::Zero();
+	S(0,0) = -1; S(0,1) = -1; S(0,2) = -1;
+	S(1,0) =  1; S(2,1) =  1; S(3,2) =  1;
+	Eigen::Matrix<double,4,3> D = S * edges_inv;
+	Eigen::Matrix<double,3,4> Dt = D.transpose();
+	int rows[3] = { index+0, index+1, index+2 };
+	int cols[4] = { prim[0], prim[1], prim[2], prim[3] };
+	for( int r=0; r<3; ++r ){
+		for( int c=0; c<4; ++c ){
+			triplets.emplace_back(rows[r], cols[c], Dt(r,c));
+		}
+	}
+	return 3;
+}
+
+} // end namespace mcl
diff --git a/extern/softbody/src/admmpd_energy.h b/extern/softbody/src/admmpd_energy.h
new file mode 100644
index 00000000000..4245c9cff9c
--- /dev/null
+++ b/extern/softbody/src/admmpd_energy.h
@@ -0,0 +1,61 @@
+
+
+
+#ifndef _ADMMPD_ENERGY_H
+#define _ADMMPD_ENERGY_H 1
+
+#include <Eigen/Sparse>
+#include <Eigen/Geometry>
+#include <vector>
+
+namespace admmpd {
+
+class Lame {
+public:
+	int m_model;
+	double m_mu;
+	double m_lambda;
+	double m_bulk_mod;
+	void set_from_youngs_poisson(double youngs, double poisson);
+	Lame();
+};
+
+class EnergyTerm {
+public:
+
+	void signed_svd(
+		const Eigen::Matrix<double,3,3> &A, 
+		Eigen::Matrix<double,3,3> &U, 
+		Eigen::Matrix<double,3,1> &S, 
+		Eigen::Matrix<double,3,3> &V);
+
+	// Updates the z and u variables for an element energy.
+	void update(
+		int index,
+		const Lame &lame,
+		double rest_volume,
+		double weight,
+		const Eigen::MatrixXd *x,
+		const Eigen::MatrixXd *Dx,
+		Eigen::MatrixXd *z,
+		Eigen::MatrixXd *u);
+
+	// Initializes tet energy, returns num rows for D
+	int init_tet(
+		int index,
+		const Lame &lame,
+		const Eigen::RowVector4i &prim,
+		const Eigen::MatrixXd *x,
+		double &volume,
+		double &weight,
+		std::vector< Eigen::Triplet<double> > &triplets);
+
+};
+
+} // end namespace admmpd
+
+#endif // _ADMMPD_ENERGY_H
+
+
+
+
diff --git a/extern/softbody/src/admmpd_lattice.cpp b/extern/softbody/src/admmpd_lattice.cpp
new file mode 100644
index 00000000000..4323f8fce33
--- /dev/null
+++ b/extern/softbody/src/admmpd_lattice.cpp
@@ -0,0 +1,229 @@
+
+
+
+#include "admmpd_lattice.h"
+#include "admmpd_math.h"
+
+//#include "vdb.h"
+
+namespace admmpd {
+using namespace Eigen;
+
+// We store our deformable data in column major to make
+// matrix-vector mults and solves faster, but we want
+// to map raw data as row major.
+inline void map_to_x3d(const std::vector<Vector3d> &x_vec, Eigen::MatrixXd *x)
+{
+	int nx = x_vec.size();
+	if (nx==0)
+	{
+		*x = MatrixXd();
+		return;
+	}
+
+	x->resize(nx,3);
+	for (int i=0; i<nx; ++i)
+	{
+		x->operator()(i,0) = x_vec[i][0];
+		x->operator()(i,1) = x_vec[i][1];
+		x->operator()(i,2) = x_vec[i][2];
+	}
+}
+
+inline void map_to_x4i(const std::vector<Vector4i> &x_vec, Eigen::MatrixXi *x)
+{
+	int nx = x_vec.size();
+	if (nx==0)
+	{
+		*x = MatrixXi();
+		return;
+	}
+
+	x->resize(nx,4);
+	for (int i=0; i<nx; ++i)
+	{
+		x->operator()(i,0) = x_vec[i][0];
+		x->operator()(i,1) = x_vec[i][1];
+		x->operator()(i,2) = x_vec[i][2];
+		x->operator()(i,3) = x_vec[i][3];
+	}
+}
+
+bool Lattice::generate(
+	const Eigen::MatrixXd &V,
+    Eigen::MatrixXd *x, // lattice vertices, n x 3
+    Eigen::MatrixXi *tets) // lattice elements, m x 4
+{
+	// All vertices enclosed in 5 tets!
+	// Will generate actual lattice in the future.
+	AlignedBox<double,3> box;
+	vtx = V;
+	int nv = vtx.rows();
+	for (int i=0; i<nv; ++i)
+	{
+		Vector3d v = vtx.row(i);
+		box.extend(v);
+	}
+	box.extend(box.min() - Vector3d::Ones() * 1e-12);
+	box.extend(box.max() + Vector3d::Ones() * 1e-12);
+
+	std::vector<Vector3d> x_vec;
+	std::vector<Vector4i> t_vec;
+	create_packed_tets(box.min(),box.max(),x_vec,t_vec);
+
+	// Copy vector data to output
+	map_to_x3d(x_vec, x);
+	map_to_x4i(t_vec, tets);
+	return compute_vtx_tet_mapping(&vtx, &vtx_to_tet, &barys, x, tets);
+
+} // end gen lattice
+
+//
+// Original source (BSD-2):
+// github.com/mattoverby/mclscene/blob/master/include/MCL/EmbeddedMesh.hpp
+//
+void Lattice::create_packed_tets(
+	const Eigen::Vector3d &min,
+	const Eigen::Vector3d &max,
+	std::vector<Vector3d> &verts,
+	std::vector<Vector4i> &tets )
+{
+
+	// Top plane, clockwise looking down
+	Vector3d a = max;
+	Vector3d b( min[0], max[1], max[2] );
+	Vector3d c( min[0], max[1], min[2] );
+	Vector3d d( max[0], max[1], min[2] );
+
+	// Bottom plan, clockwise looking down
+	Vector3d e( max[0], min[1], max[2] );
+	Vector3d f( min[0], min[1], max[2] );
+	Vector3d g( min[0], min[1], min[2] );
+	Vector3d h( max[0], min[1], min[2] );
+
+	// Add the verts
+	int nv = verts.size();
+	verts.emplace_back( a ); // 0
+	verts.emplace_back( b ); // 1
+	verts.emplace_back( c ); // 2
+	verts.emplace_back( d ); // 3
+	verts.emplace_back( e ); // 4
+	verts.emplace_back( f ); // 5
+	verts.emplace_back( g ); // 6
+	verts.emplace_back( h ); // 7
+
+	// Pack 5 tets into the cube
+	Vector4i t0( 0, 5, 7, 4 );
+	Vector4i t1( 5, 7, 2, 0 );
+	Vector4i t2( 5, 0, 2, 1 );
+	Vector4i t3( 7, 2, 0, 3 );
+	Vector4i t4( 5, 2, 7, 6 );
+	Vector4i offset(nv,nv,nv,nv);
+
+	// Add the tets
+	tets.emplace_back( t0+offset );
+	tets.emplace_back( t1+offset );
+	tets.emplace_back( t2+offset );
+	tets.emplace_back( t3+offset );
+	tets.emplace_back( t4+offset );
+
+//vdb_point(a[0],a[1],a[2]);
+//vdb_point(b[0],b[1],b[2]);
+//vdb_point(c[0],c[1],c[2]);
+//vdb_point(d[0],d[1],d[2]);
+//vdb_point(e[0],e[1],e[2]);
+//vdb_point(f[0],f[1],f[2]);
+//vdb_point(g[0],g[1],g[2]);
+//vdb_point(h[0],h[1],h[2]);
+//vdb_line(float x0, float y0, float z0, 
+//             float x1, float y1, float z1);
+
+} // end create packed tets
+
+bool Lattice::compute_vtx_tet_mapping(
+	const Eigen::MatrixXd *vtx_, // embedded vertices, p x 3
+	Eigen::VectorXi *vtx_to_tet_, // what tet vtx is embedded in, p x 1
+	Eigen::MatrixXd *barys_, // barycoords of the embedding, p x 4
+	const Eigen::MatrixXd *x_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list