简介

有限元方法, 把物体分割成一个个有体积的单元来模拟.

线性有限元方法在二维空间中把物体分割成三角形/四边形, 在三维空间中把物体分割成四面体/六面体.

有限元方法由能量对位置求导得到力,有限体积方法对 traction vector 积分得到力。

TIPS

STVK模型, PPT中写错了, 正确的在 https://www.bilibili.com/read/cv14754926 上有讲解

\[W=\frac{s_{0}}{8}(I-3)^{2}+\frac{s_{1}}{4}(I I-2 I+3)
\]

核心参考PPT

SVTK实现



FVM实现, 说实话 我也不知道 下面实现的是有限元还是有限体积, 逻辑上应该是有限体积

关于Laplacian 速度平滑

就是V_SUM 周围顶点速度的和

V_NUM 周围顶点的个数

附录: 师弟代码

code

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.IO; public class FVM : MonoBehaviour
{
float dt = 0.003f;
float mass = 1;
float stiffness_0 = 7500.0f;
float stiffness_1 = 5000.0f;
float damp = 0.999f; float Un = 0.5f; // for collision
float Ut = 0.5f; // for collision
Vector3 P = new Vector3(0, -3, 0);
Vector3 N = new Vector3(0, 1, 0); int[] Tet; //四面体数据
int tet_number; //The number of tetrahedra 四面体数目 Vector3[] Force; //力
Vector3[] V; //速度
Vector3[] X; //点数据
int number; //The number of vertices Matrix4x4[] inv_Dm; //For Laplacian smoothing.
Vector3[] V_sum;
int[] V_num; SVD svd = new SVD(); // Start is called before the first frame update
void Start()
{
// FILO IO: Read the house model from files.
// The model is from Jonathan Schewchuk's Stellar lib.
{
string fileContent = File.ReadAllText("Assets/house2.ele");
string[] Strings = fileContent.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); tet_number = int.Parse(Strings[0]);
Tet = new int[tet_number * 4]; for (int tet = 0; tet < tet_number; tet++)
{
Tet[tet * 4 + 0] = int.Parse(Strings[tet * 5 + 4]) - 1;
Tet[tet * 4 + 1] = int.Parse(Strings[tet * 5 + 5]) - 1;
Tet[tet * 4 + 2] = int.Parse(Strings[tet * 5 + 6]) - 1;
Tet[tet * 4 + 3] = int.Parse(Strings[tet * 5 + 7]) - 1;
}
}
{
string fileContent = File.ReadAllText("Assets/house2.node");
string[] Strings = fileContent.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
number = int.Parse(Strings[0]);
X = new Vector3[number];
for (int i = 0; i < number; i++)
{
X[i].x = float.Parse(Strings[i * 5 + 5]) * 0.4f;
X[i].y = float.Parse(Strings[i * 5 + 6]) * 0.4f;
X[i].z = float.Parse(Strings[i * 5 + 7]) * 0.4f;
}
//Centralize the model.
Vector3 center = Vector3.zero;
for (int i = 0; i < number; i++) center += X[i];
center = center / number;
for (int i = 0; i < number; i++)
{
X[i] -= center;
float temp = X[i].y;
X[i].y = X[i].z;
X[i].z = temp;
}
}
/*tet_number=1;
Tet = new int[tet_number*4];
Tet[0]=0;
Tet[1]=1;
Tet[2]=2;
Tet[3]=3; number=4;
X = new Vector3[number];
V = new Vector3[number];
Force = new Vector3[number];
X[0]= new Vector3(0, 0, 0);
X[1]= new Vector3(1, 0, 0);
X[2]= new Vector3(0, 1, 0);
X[3]= new Vector3(0, 0, 1);*/ //Create triangle mesh.
Vector3[] vertices = new Vector3[tet_number * 12];
int vertex_number = 0;
for (int tet = 0; tet < tet_number; tet++)
{
vertices[vertex_number++] = X[Tet[tet * 4 + 0]];
vertices[vertex_number++] = X[Tet[tet * 4 + 2]];
vertices[vertex_number++] = X[Tet[tet * 4 + 1]]; vertices[vertex_number++] = X[Tet[tet * 4 + 0]];
vertices[vertex_number++] = X[Tet[tet * 4 + 3]];
vertices[vertex_number++] = X[Tet[tet * 4 + 2]]; vertices[vertex_number++] = X[Tet[tet * 4 + 0]];
vertices[vertex_number++] = X[Tet[tet * 4 + 1]];
vertices[vertex_number++] = X[Tet[tet * 4 + 3]]; vertices[vertex_number++] = X[Tet[tet * 4 + 1]];
vertices[vertex_number++] = X[Tet[tet * 4 + 2]];
vertices[vertex_number++] = X[Tet[tet * 4 + 3]];
} int[] triangles = new int[tet_number * 12];
for (int t = 0; t < tet_number * 4; t++)
{
triangles[t * 3 + 0] = t * 3 + 0;
triangles[t * 3 + 1] = t * 3 + 1;
triangles[t * 3 + 2] = t * 3 + 2;
}
Mesh mesh = GetComponent<MeshFilter>().mesh;
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals(); V = new Vector3[number];
Force = new Vector3[number];
V_sum = new Vector3[number];
V_num = new int[number]; for (int tet = 0; tet < tet_number; tet++)
{
V_num[Tet[tet * 4]] += 4;
V_num[Tet[tet * 4 + 1]] += 4;
V_num[Tet[tet * 4 + 2]] += 4;
V_num[Tet[tet * 4 + 3]] += 4;
}
//TODO: Need to allocate and assign inv_Dm
inv_Dm = new Matrix4x4[tet_number];
for (int tet = 0; tet < tet_number; tet++)
{
inv_Dm[tet] = Build_Edge_Matrix(tet).inverse;
//Debug.Log("inv_Dm:" + inv_Dm[tet]);
}
} Matrix4x4 Build_Edge_Matrix(int tet)
{
Matrix4x4 ret = Matrix4x4.zero;
//TODO: Need to build edge matrix here. ret[0, 0] = X[Tet[tet * 4]][0] - X[Tet[tet * 4 + 1]][0];
ret[1, 0] = X[Tet[tet * 4]][1] - X[Tet[tet * 4 + 1]][1];
ret[2, 0] = X[Tet[tet * 4]][2] - X[Tet[tet * 4 + 1]][2]; ret[0, 1] = X[Tet[tet * 4]][0] - X[Tet[tet * 4 + 2]][0];
ret[1, 1] = X[Tet[tet * 4]][1] - X[Tet[tet * 4 + 2]][1];
ret[2, 1] = X[Tet[tet * 4]][2] - X[Tet[tet * 4 + 2]][2]; ret[0, 2] = X[Tet[tet * 4]][0] - X[Tet[tet * 4 + 3]][0];
ret[1, 2] = X[Tet[tet * 4]][1] - X[Tet[tet * 4 + 3]][1];
ret[2, 2] = X[Tet[tet * 4]][2] - X[Tet[tet * 4 + 3]][2]; ret[3, 3] = 1; return ret;
} Matrix4x4 M_Division(Matrix4x4 m, float scale)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
m[i, j] /= scale;
}
} return m;
} Matrix4x4 M_Multipy(Matrix4x4 m, float scale)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
m[i, j] *= scale;
}
} return m;
} Matrix4x4 M_addtion(Matrix4x4 m1, Matrix4x4 m2)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
m1[i, j] += m2[i, j];
}
} return m1;
} Matrix4x4 M_Dec(Matrix4x4 m1, Matrix4x4 m2)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
m1[i, j] -= m2[i, j];
}
} return m1;
} float TR(Matrix4x4 m)
{
float res = 0f;
res += m.m00;
res += m.m11;
res += m.m22;
return res;
} void Update_Collision_Point(int idx, float distance, Vector3 N)
{ X[idx] -= distance * N;
float viN = Vector3.Dot(V[idx], N);
if (viN >= 0) return;
Vector3 v_Ni = viN * N; // (vi * N)N 反弹面的分量
Vector3 v_Ti = V[idx] - v_Ni; // 沿着面的分量 //定义摩擦系数a
float a = Mathf.Max(1.0f - Ut * (1.0f + Un) * v_Ni.magnitude / v_Ti.magnitude, 0.0f); //计算新速度
Vector3 v_Ni_new = -Un * v_Ni;
Vector3 v_Ti_new = a * v_Ti;
V[idx] = v_Ni_new + v_Ti_new; } Matrix4x4 SVtk(Matrix4x4 F)
{
Matrix4x4 P = Matrix4x4.zero;
Matrix4x4 U = Matrix4x4.zero;
Matrix4x4 S = Matrix4x4.zero;
Matrix4x4 V = Matrix4x4.zero;
Matrix4x4 Plamda = Matrix4x4.zero;
svd.svd(F, ref U, ref S, ref V); float lamda0 = S[0, 0];
float lamda1 = S[1, 1];
float lamda2 = S[2, 2]; float Ic = lamda0 * lamda0 + lamda1 * lamda1 +
lamda2 * lamda2; float Ic_l0 = 2f * lamda0;
float Ic_l1 = 2f * lamda1;
float Ic_l2 = 2f * lamda2; //float IIc_l0 = 2f * lamda0 * (lamda1 * lamda1 + lamda2 * lamda2);
//float IIc_l1 = 2f * lamda1 * (lamda0 * lamda0 + lamda2 * lamda2);
//float IIc_l2 = 2f * lamda2 * (lamda1 * lamda1 + lamda0 * lamda0); float IIc_l0 = 4f * lamda0 * lamda0 * lamda0;
float IIc_l1 = 4f * lamda1 * lamda1 * lamda1;
float IIc_l2 = 4f * lamda2 * lamda2 * lamda2; //float IIc_l0 = 4f * lamda0 * lamda0 * lamda0 * lamda1 * lamda1 * lamda1 * lamda1 * lamda2 * lamda2 * lamda2 * lamda2;
//float IIc_l1 = 4f * lamda1 * lamda1 * lamda1 * lamda0 * lamda0 * lamda0 * lamda0 * lamda2 * lamda2 * lamda2 * lamda2;
//float IIc_l2 = 4f * lamda2 * lamda2 * lamda2 * lamda1 * lamda1 * lamda1 * lamda1 * lamda0 * lamda0 * lamda0 * lamda0; Plamda[0, 0] = stiffness_0 * (Ic - 3f) * Ic_l0 /4f +
stiffness_1 * (IIc_l0 - 2 * Ic_l0) / 4f;
Plamda[1, 1] = stiffness_0 * (Ic - 3f) * Ic_l1 /4f +
stiffness_1 * (IIc_l1 - 2 * Ic_l1) / 4f;
Plamda[2, 2] = stiffness_0 * (Ic - 3f) * Ic_l2 /4f +
stiffness_1 * (IIc_l2 - 2 * Ic_l2) / 4f;
Plamda[3, 3] = 1f;
P = U * Plamda * V.transpose;
return P;
} void _Update()
{
// Jump up.
if (Input.GetKeyDown(KeyCode.Space))
{
for (int i = 0; i < number; i++)
V[i].y += 0.2f;
} for (int i = 0; i < number; i++)
{
//TODO: Add gravity to Force.
Force[i] = new Vector3(0, -9.8f, 0);
} for (int tet = 0; tet < tet_number; tet++)
{
Matrix4x4 I = Matrix4x4.identity;
//TODO: Deformation Gradient
Matrix4x4 F = Build_Edge_Matrix(tet);
F = F * inv_Dm[tet]; //TODO: Green Strain
Matrix4x4 G = M_Division(M_Dec(F.transpose * F, I)
, 2f); //TODO: Second PK Stress Matrix4x4 S = M_addtion(M_Multipy(G,
stiffness_1 * 2f), M_Multipy(I, TR(G) *
stiffness_0));
Matrix4x4 P = F * S; //SVTK
P = SVtk(F); //TODO: Elastic Force
Matrix4x4 EF = M_Multipy(P * (inv_Dm[tet].transpose)
, -1f / (6f * inv_Dm[tet].determinant));
//Debug.Log("EF:" + EF);
Force[Tet[tet * 4 + 1]][0] += EF[0, 0];
Force[Tet[tet * 4 + 1]][1] += EF[1, 0];
Force[Tet[tet * 4 + 1]][2] += EF[2, 0]; Force[Tet[tet * 4 + 2]][0] += EF[0, 1];
Force[Tet[tet * 4 + 2]][1] += EF[1, 1];
Force[Tet[tet * 4 + 2]][2] += EF[2, 1]; Force[Tet[tet * 4 + 3]][0] += EF[0, 2];
Force[Tet[tet * 4 + 3]][1] += EF[1, 2];
Force[Tet[tet * 4 + 3]][2] += EF[2, 2]; Force[Tet[tet * 4]][0] += -EF[0, 0] - EF[0, 1] - EF[0, 2];
Force[Tet[tet * 4]][1] += -EF[1, 0] - EF[1, 1] - EF[1, 2];
Force[Tet[tet * 4]][2] += -EF[2, 0] - EF[2, 1] - EF[2, 2]; } for (int i = 0; i < number; i++)
{
//TODO: Update X and V here.
V[i] += Force[i] * dt;
V[i] *= damp;
X[i] += V[i] * dt; //TODO: (Particle) collision with floor.
float distance = Vector3.Dot(X[i] - P, N);
if (distance < 0)
{
Update_Collision_Point(i, distance, N);
}
V_sum[i] = Vector3.zero;
} //laplacian
for (int tet = 0; tet < tet_number; tet++)
{
Vector3 v0 = V[Tet[tet * 4]];
Vector3 v1 = V[Tet[tet * 4 + 1]];
Vector3 v2 = V[Tet[tet * 4 + 2]];
Vector3 v3 = V[Tet[tet * 4 + 3]];
Vector3 vs = v0 + v1 + v2 + v3;
V_sum[Tet[tet * 4]] += vs;
V_sum[Tet[tet * 4 + 1]] += vs;
V_sum[Tet[tet * 4 + 2]] += vs;
V_sum[Tet[tet * 4 + 3]] += vs; } for (int i = 0; i < number; i++)
{
V[i] = V_sum[i] / V_num[i]; }
Un = Mathf.Max(0.0f, Un - 0.005f);
} // Update is called once per frame
void Update()
{
for (int l = 0; l < 10; l++)
_Update(); // Dump the vertex array for rendering.
Vector3[] vertices = new Vector3[tet_number * 12];
int vertex_number = 0;
for (int tet = 0; tet < tet_number; tet++)
{
vertices[vertex_number++] = X[Tet[tet * 4 + 0]];
vertices[vertex_number++] = X[Tet[tet * 4 + 2]];
vertices[vertex_number++] = X[Tet[tet * 4 + 1]];
vertices[vertex_number++] = X[Tet[tet * 4 + 0]];
vertices[vertex_number++] = X[Tet[tet * 4 + 3]];
vertices[vertex_number++] = X[Tet[tet * 4 + 2]];
vertices[vertex_number++] = X[Tet[tet * 4 + 0]];
vertices[vertex_number++] = X[Tet[tet * 4 + 1]];
vertices[vertex_number++] = X[Tet[tet * 4 + 3]];
vertices[vertex_number++] = X[Tet[tet * 4 + 1]];
vertices[vertex_number++] = X[Tet[tet * 4 + 2]];
vertices[vertex_number++] = X[Tet[tet * 4 + 3]];
}
Mesh mesh = GetComponent<MeshFilter>().mesh;
mesh.vertices = vertices;
mesh.RecalculateNormals();
}
}

image

参考链接

https://zhuanlan.zhihu.com/p/447263178

https://github.com/Teafox-Yang/GAMES103_HW_TEAFOX

https://www.bilibili.com/read/cv14754926

GAMES103 FEM 有限元模拟弹性房子的更多相关文章

  1. Java设计模式--模板方法模式

    定义: 模板模式是一种行为设计模式,使用了JAVA的继承机制,在抽象类中定义一个模板方法,该方法引用了若干个抽象方法(由子类实现)或具体方法(子类可以覆盖重写).它的实现思路是,创建一个桩方法,并且定 ...

  2. 实现了一个简单的cage变形器

    今天实现了一个简单变形器,可以用一个网格的形状影响另一个网格的形状. 如图,蓝色网格的形状被灰色网格操控. 当前的算法非常简单,就是计算蓝色网格每个点到灰色网格每个点的距离,以距离x次方的倒数作为权重 ...

  3. 考虑与Maya结合

    今天改进了Hessian各块的计算代码,减少了一些内存操作.下一步准备把模拟平台与Maya结合,这样就可以利用Maya丰富的变形算法了. 这一步需要考虑以下问题: 1.把场景设置为某一帧.这一点可以用 ...

  4. 并行编程之CountdownEvent的用法

    教程:http://blog.gkarch.com/threading/part5.html#the-parallel-class http://www.cnblogs.com/huangxinche ...

  5. [C#]『CountdownEvent』任务并行库使用小计

    System.Threading.CountdownEvent  是一个同步基元,它在收到一定次数的信号之后,将会解除对其等待线程的锁定. CountdownEvent  专门用于以下情况:您必须使用 ...

  6. .Net并行编程之同步机制

     一:Barrier(屏障同步) 二:spinLock(自旋锁) 信号量  一:CountdownEvent 虽然通过Task.WaitAll()方法也可以达到线程同步的目的. 但是Countdown ...

  7. D3、EChart、HighChart绘图demol

    1.echarts:   <!DOCTYPE html>   <html>   <head>   <meta charset="utf-8" ...

  8. 西南交通大学结构服役安全及力学基础创新团队在Wiley出版英文专著(转载)

    近日,西南交通大学力学与工程学院康国政教授与阚前华副教授受邀由John Wiley & Sons Ltd公司出版了英文专著 “Cyclic plasticity of Engineering  ...

  9. 软件项目技术点(1)——d3.interpolateZoom-在两个点之间平滑地缩放平移

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 软件参考d3的知识点 我们在软件中主要用到d3.js的核心函数d3.interpolateZoom - 在两个点之间平滑地缩放平移.请 ...

  10. D3js-API介绍【中】

    JavaScript可视化图表库D3.js API中文參考,d3.jsapi D3 库所提供的全部 API 都在 d3 命名空间下.d3 库使用语义版本号命名法(semantic versioning ...

随机推荐

  1. 剑气纵横千行码:AI写就的设计模式侠客行助您仗剑走天涯

    烟火里的江湖旧忆 暮色里,代码侠的电动车在巷口急刹,外卖箱里的热汤晃出细响,恍惚间竟像当年工厂堡锻造炉的轰鸣.难得休息之余,他抹了把额头的汗,扶了扶常开网约车的腰,摸了摸自己晒黑的脸,偶感那颠炒粉的手 ...

  2. Innodb快速复习

    放一张官方架构图: 参考文章: 一文带你了解MySQL之InnoDB_Buffer_Pool-阿里云开发者社区这一篇buffer pool讲解的很好 [动画演示:MySQL的BufferPool和Ch ...

  3. maven-helper解决依赖冲突

    idea中可以使用maven-helper解决依赖冲突

  4. 活动箭线的"总时差和专用时差"

    总时差:后大 - 前小 - 作业时间 专用时差:后小 - 前大 - 作业时间

  5. 结点的"最早开始和最晚开始和最早完成和最晚完成"

    最早:方块表示 最晚:三角形表示 最早开始:2 最晚开始:15-5=10 最早完成:2+5=7 最晚完成:15 案例1 案例2

  6. django笔记(3)-数据库操作

    一:路由系统    url    1.url(r'^index/', views.index),url(r'^home/',views.Home.as_view()), 一个url对应一个函数或一个类 ...

  7. C#之线程基础

    创建线程 using System; using System.Threading; using System.Threading.Tasks; namespace threadDemo { clas ...

  8. 用脚手架创建odoo15项目

    Odoo 提供了一种机制来帮助建立一个新模块,odoo-bin有一个子命令脚手架来创建一个空模块 命令: $ odoo-bin scaffold <module name> <whe ...

  9. CentOS7 vsftpd服务搭建与详解

    FTP介绍 文件传输协议(File Transfer Protocol,FTP),基于该协议FTP客户端与服务端可以实现共享文件.上传文件.下载文件. FTP 基于TCP协议生成一个虚拟的连接,主要用 ...

  10. java如何启动时定义并初始化一个全局变量(内存中)

    前言 java如何启动时定义并初始化一个全局变量(内存中),项目启动时,通过读取配置文件来构建一个实体类对象,然后在之后可以直接使用,而不是每次使用都要进行构建 前置准备 实体类结构 package ...