GAMES103 cloth 隐式积分法
简介
隐式积分法
显示积分简单而言是通过, 过去的求解未来. 而隐式积分, 简单而言是我要求解现在, 但是我的未知量中也有现在的未知量. 简单而言就是需要通过方程组的思想来进行求解.
参考文献
代码参考师弟 ~~
对于cloth问题, 简而言之, 有两个变量需要我们求解. 即速度v和位置x.
\]
上述为了求解\(x^{[1]}\), 我们用到了\(\mathbf{f}^{[1]}\), 两个都是未来的变量, 需要通过方程组来进行求解.
数学家将隐式积分的问题转换成求解
\]
碰撞检测
使用基于脉冲法. 其实在lab2.pdf中也有讲解
\]
求解函数
\]
中的\(\Delta \mathbf{x}\)来计算新的坐标和位移
A
A 就是 \(\left(\frac{1}{\Delta t^{2}} \mathbf{M}+\mathbf{H}\left(\mathbf{x}^{(k)}\right)\right)\)
其中的 hessian 矩阵比较难求. 作者通过简化A
A =
\]
G 梯度
G 其实是 -b
为什么梯度就是 -b 呢??
因为作者使用的是牛顿迭代法
牛顿迭代法有一个特性
\]
一个函数的一阶导数等于其一阶导数+二阶导数×偏差.
也就是 \(-F^{\prime}(x) = F^{\prime \prime}\left(x^{(k)}\right)\left(x-x^{(k)}\right)\)
其中\(-F^{\prime}(x)\)
就是
\]
而 b 就是 \(-F^{\prime}(x)\)
G 中包含了 \(\mathbf{f}\left(\mathbf{x}^{(k)}\right)\) 包含两个力, 一个是重力, 另一个是弹簧的弹力.
image
核心公式
code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class implicit_model : MonoBehaviour
{
float t = 0.0333f;
float mass = 1;
float damping = 0.99f;
float rho = 0.995f;
float spring_k = 8000;
int[] E; // 边对
float[] L; // 初始边长度
Vector3[] V;
Vector3 g = new Vector3(0, -9.8f, 0); // 重力
float r = 2.7f; // 球半径
// Start is called before the first frame update
void Start()
{
Mesh mesh = GetComponent<MeshFilter> ().mesh;
//Resize the mesh.
int n=21;
Vector3[] X = new Vector3[n*n];
Vector2[] UV = new Vector2[n*n];
int[] triangles = new int[(n-1)*(n-1)*6];
for(int j=0; j<n; j++)
for(int i=0; i<n; i++)
{
X[j*n+i] =new Vector3(5-10.0f*i/(n-1), 0, 5-10.0f*j/(n-1));
UV[j*n+i]=new Vector3(i/(n-1.0f), j/(n-1.0f));
}
int t=0;
for(int j=0; j<n-1; j++)
for(int i=0; i<n-1; i++)
{
triangles[t*6+0]=j*n+i;
triangles[t*6+1]=j*n+i+1;
triangles[t*6+2]=(j+1)*n+i+1;
triangles[t*6+3]=j*n+i;
triangles[t*6+4]=(j+1)*n+i+1;
triangles[t*6+5]=(j+1)*n+i;
t++;
}
mesh.vertices=X;
mesh.triangles=triangles;
mesh.uv = UV;
mesh.RecalculateNormals ();
//Construct the original E
int[] _E = new int[triangles.Length*2];
for (int i=0; i<triangles.Length; i+=3)
{
_E[i*2+0]=triangles[i+0];
_E[i*2+1]=triangles[i+1];
_E[i*2+2]=triangles[i+1];
_E[i*2+3]=triangles[i+2];
_E[i*2+4]=triangles[i+2];
_E[i*2+5]=triangles[i+0];
}
//Reorder the original edge list
for (int i=0; i<_E.Length; i+=2)
if(_E[i] > _E[i + 1])
Swap(ref _E[i], ref _E[i+1]);
//Sort the original edge list using quicksort
Quick_Sort (ref _E, 0, _E.Length/2-1);
int e_number = 0;
for (int i=0; i<_E.Length; i+=2)
if (i == 0 || _E [i + 0] != _E [i - 2] || _E [i + 1] != _E [i - 1])
e_number++;
E = new int[e_number * 2];
for (int i=0, e=0; i<_E.Length; i+=2)
if (i == 0 || _E [i + 0] != _E [i - 2] || _E [i + 1] != _E [i - 1])
{
E[e*2+0]=_E [i + 0];
E[e*2+1]=_E [i + 1];
e++;
}
L = new float[E.Length/2];
for (int e=0; e<E.Length/2; e++)
{
int v0 = E[e*2+0];
int v1 = E[e*2+1];
L[e]=(X[v0]-X[v1]).magnitude;
}
V = new Vector3[X.Length];
for (int i=0; i<V.Length; i++)
V[i] = new Vector3 (0, 0, 0);
}
void Quick_Sort(ref int[] a, int l, int r)
{
int j;
if(l<r)
{
j=Quick_Sort_Partition(ref a, l, r);
Quick_Sort (ref a, l, j-1);
Quick_Sort (ref a, j+1, r);
}
}
int Quick_Sort_Partition(ref int[] a, int l, int r)
{
int pivot_0, pivot_1, i, j;
pivot_0 = a [l * 2 + 0];
pivot_1 = a [l * 2 + 1];
i = l;
j = r + 1;
while (true)
{
do ++i; while( i<=r && (a[i*2]<pivot_0 || a[i*2]==pivot_0 && a[i*2+1]<=pivot_1));
do --j; while( a[j*2]>pivot_0 || a[j*2]==pivot_0 && a[j*2+1]> pivot_1);
if(i>=j) break;
Swap(ref a[i*2], ref a[j*2]);
Swap(ref a[i*2+1], ref a[j*2+1]);
}
Swap (ref a [l * 2 + 0], ref a [j * 2 + 0]);
Swap (ref a [l * 2 + 1], ref a [j * 2 + 1]);
return j;
}
void Swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
void Collision_Handling()
{
Mesh mesh = GetComponent<MeshFilter> ().mesh;
Vector3[] X = mesh.vertices;
GameObject sphere = GameObject.Find("Sphere");
Vector3 c = sphere.transform.position;
//Handle colllision.
for(int i=0; i<X.Length; i++)
{
if (i == 0 || i == 20) continue;
float distance = (X[i] - c).magnitude;
if(distance < r)
{
V[i] += (c + r * (X[i] - c) / distance - X[i]) / t; // 需要一个很小的速度偏差
X[i] = c + r * (X[i] - c) / distance;
}
}
mesh.vertices = X;
}
void Get_Gradient(Vector3[] X, Vector3[] X_hat, float t, Vector3[] G)
{
//Momentum and Gravity.
for(int i=0; i<G.Length; i++)
{
G[i] = (X[i] - X_hat[i]) * mass / (t * t) - g * mass;
}
//Spring Force.
for(int ei = 0; ei < L.Length; ei++)
{
int i = E[ei * 2];
int j = E[ei * 2 + 1];
Vector3 xi_xj = X[i] - X[j];
float len_ij = L[ei] / xi_xj.magnitude;
Vector3 t_ij = spring_k * (1 - len_ij) * xi_xj;
G[i] += t_ij;
G[j] -= t_ij;
}
}
// Update is called once per frame
void Update ()
{
Mesh mesh = GetComponent<MeshFilter> ().mesh;
Vector3[] X = mesh.vertices;
Vector3[] last_X = new Vector3[X.Length];
Vector3[] X_hat = new Vector3[X.Length]; // x = x + vi * t
Vector3[] G = new Vector3[X.Length]; // Gradient
Vector3[] delta_x = new Vector3[X.Length];
Vector3[] last_delta_x = new Vector3[X.Length];
Vector3[] old_delta_x = new Vector3[X.Length];
//Initial Setup.
// 更新速度和位置
for (int i=0; i<X.Length; i++)
{
V[i] *= damping;
last_X[i] = X[i];
X_hat[i] = X[i] + t * V[i];
X[i] = X_hat[i];
}
for(int k=0; k<32; k++)
{
Get_Gradient(X, X_hat, t, G);
// chebyshev
float A = mass / (t * t) + 4 * spring_k;
float w = 0;
float rest = 0;
for(int i = 0; i<X.Length; i++)
{
delta_x[i] = new Vector3(0, 0, 0);
last_delta_x[i] = new Vector3(0, 0, 0);
}
// iter
for(int j=0; j<50; j++)
{
rest = 0;
for(int i=0; i<X.Length; i++)
{
rest += (-delta_x[i] * A - G[i]).sqrMagnitude;
}
if(Mathf.Sqrt(rest) < 0.00001)
{
Debug.Log("Iter :" + k);
break;
}
if(j == 0)
{
w = 1;
}else if(j == 1)
{
w = 2 / (2 - rho * rho);
}else
{
w = 4 / (4 - rho * rho * w);
}
for(int i=0; i<X.Length; i++)
{
old_delta_x[i] = delta_x[i];
delta_x[i] += -delta_x[i] - G[i] / A;
delta_x[i] = w * delta_x[i] + (1 - w) * last_delta_x[i];
last_delta_x[i] = old_delta_x[i];
}
}
Debug.Log("rest:" + rest);
//Update X by gradient.
for(int i=0; i<X.Length; i++)
{
if (i == 0 || i == 20) continue;
X[i] += delta_x[i];
}
}
//Finishing.
for(int i=0; i<V.Length; i++)
{
V[i] += (X[i] - X_hat[i]) / t;
}
mesh.vertices = X;
Collision_Handling ();
mesh.RecalculateNormals ();
}
}
GAMES103 cloth 隐式积分法的更多相关文章
- SQL Server中提前找到隐式转换提升性能的办法
http://www.cnblogs.com/shanksgao/p/4254942.html 高兄这篇文章很好的谈论了由于数据隐式转换造成执行计划不准确,从而造成了死锁.那如果在事情出现之前 ...
- js条件判断时隐式类型转换
Javascript 中,数字 0 为假,非0 均为真 在条件判断运算 == 中的转换规则是这样的: 如果比较的两者中有布尔值(Boolean),会把 Boolean 先转换为对应的 Number,即 ...
- 非RootLayer的隐式动画
非RootLayer都有隐式动画,默认0.25秒. // 1.开启 [CATransaction begin]; // 2.设置关闭 YES-关闭:NO-开启 [CATransaction setDi ...
- C#接口的显示和隐式实现
早上骑车上班走到半路发现手机忘带了,这年代兜里没装一分现金,吃饭都要刷手机,上班时间无聊了不能玩手机更是大问题,所以果断掉头拿手机.取完手机刚出门看这天阴沉沉的貌似要下雨,没雨衣,骑车又不能打伞,上次 ...
- MySQL隐式转化整理
MySQL隐式转化整理 前几天在微博上看到一篇文章:价值百万的 MySQL 的隐式类型转换感觉写的很不错,再加上自己之前也对MySQL的隐式转化这边并不是很清楚,所以就顺势整理了一下.希望对大家有所帮 ...
- 在Android中Intent的概念及应用(一)——显示Intent和隐式Intent
Intent寻找目标组件的两种方式: 显式Intent:通过指定Intent组件名称来实现的,它一般用在知道目标组件名称的前提下,一般是在相同的应用程序内部实现的. 隐式Intent:通过Intent ...
- C#中的隐式类型var——详细示例解析
从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,它的具体类型由编译器根据上下文推断而出. 下面就让我来总结下隐式类型的一些特点: 1.va ...
- JSP页面以及JSP九大隐式对象
JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术. JSP这门技术的最大的特点在于,写jsp就像在写html,但它相比 ...
- .NET中那些所谓的新语法之一:自动属性、隐式类型、命名参数与自动初始化器
开篇:在日常的.NET开发学习中,我们往往会接触到一些较新的语法,它们相对以前的老语法相比,做了很多的改进,简化了很多繁杂的代码格式,也大大减少了我们这些菜鸟码农的代码量.但是,在开心欢乐之余,我们也 ...
- 每天多一点(2016.12.04)》Javascript隐式转换
乱想 javascript为什么需要隐式转换?如果没有会出现什么情况? 找了一圈没有看到关于这个的讨论,只好自己研究了,可能不一定正确,自行辨知. 郁闷就是郁闷在好好的,为什么要搞个隐式转换,一般来讲 ...
随机推荐
- 为了掌握设计模式,开发了一款Markdown 文本编辑器软件(已开源)
设计模式实战项目:Markdown 文本编辑器软件开发(已开源) 一.项目简介 项目名称:YtyMark-java 本项目是一款基于 Java 语言 和 JavaFX 图形界面框架 开发的 Markd ...
- VUE——环境搭建
VUE--环境搭建 npm: Nodejs下的包管理器. webpack: 它主要的用途是通过CommonJS的语法把所有浏览器端需要发布的静态资源做相应的准备,比如资源的合并和打包. vue-cli ...
- 【MOOC】华中科技大学操作系统慕课答案-单元作业+第1~2章开放性思考题
单元作业答案如果没大问题的话,多半是直接摘抄自PPT. 文章目录 第一章 操作系统概述 单元作业(1) 开放性思考题 第二章 操作系统逻辑结构 单元作业 开放性思考题 第三章 操作系统用户界面 单元作 ...
- storageclass和本地持久化存储
StorageClass 之前我们部署了PV 和 PVC 的使用方法,但是前面的 PV 都是静态的,什么意思?就是我要使用的一个 PVC 的话就必须手动去创建一个 PV,我们也说过这种方式在很大程度上 ...
- vue3 学习-初识体验-常见指令v-for和v-model
继续通过小案例来体验一些常用的指令, 以经典的todolist进行展示. 首先呢通过 v-for 指令进行dom循环. v-for 通常是在循环dom的编写的同时遍历数据进行填充. <!DOCT ...
- 网络编程:poll
原理 和select类似,只是描述fd集合的方式不同,poll使用pollfd结构而非select的fd_set结构. 管理多个描述符也是进行轮询,根据描述符的状态进行处理,但poll没有最大文件描述 ...
- 梯度下降(Gradient Descent)法
梯度下降法(Gradient Descent)是求解无约束最优化问题最常用的方法之一,它是一种迭代方法,每一步的主要操作就是求解目标函数的梯度向量,将当前位置的负梯度方向作为搜索方向. 直观的表示可用 ...
- Error: A JNI error has occurred, please check your installation and try again Exception in thread "main" java.lang.UnsupportedClassVersionError: HelloWorld has been compiled by a more
一个新手容易遇到的问题,电脑上装了多个版本的java,比如8和11,导致javac和java的版本不一样 在控制面板里将其他版本卸载,留个8就行 然后在环境变量里重新配置一下就ok
- 如何在AutoCAD Electrical中修改项目描述中的行号
默认情况下,项目描述对话框中都会以行号+数字的形式显示,如下图所示: 1.打开记事本程序,按照以下格式收入文字: LINE1=设计 LINE2=制图 LINE3=校对 LINE4=审核 LINE5=工 ...
- VS调试DMP文件
开启DMP文件(引用:https://www.cnblogs.com/netck/p/10483933.html) 1.开启系统服务(Windows Error Reporting Service) ...