简介

作业1简单实现了一个以一定初始速度和角速度的模型和墙壁碰撞的效果.

总共讲解了三种算法

  1. impulse (脉冲法)

  2. Shape Matching(基于形状保持的算法, 不包含物理特性)

  3. Penalty methods

Shape Matching 可以说是最简单的方法之一

因为完全不涉及角速度. 基础逻辑理论就是, 当模型和墙壁发生碰撞的时候.这些碰撞的粒子会产生相反的形变但是. 我们强制将其整理保持形状的一致性. 就是先形变. 再变回来.

由于形变的步骤. 是中间步骤. 不会展示出来. 所以效果还是挺好的.

Image





TIPS

code

using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class Rigid_Bunny_by_Shape_Matching : MonoBehaviour
{
public bool launched = false;
Vector3[] X; // world position
Vector3[] Y; // temp world position
Vector3[] Q; // Local coordinates
Vector3[] V; // speed
Vector3[] OldX;
Matrix4x4 QQt = Matrix4x4.zero;
Vector3 G = new Vector3(0.0f, -9.8f, 0.0f);
float linear_decay = 0.999f;
Vector3 ground = new Vector3(0, 0.01f, 0);
Vector3 groundNormal = new Vector3(0, 1, 0);
Vector3 wall = new Vector3(2.01f, 0, 0);
Vector3 wallNormal = new Vector3(-1, 0, 0);
float mu_T = 0.5f; // μ_T may be coefficient of air resistance
float mu_N = 5.0f; // μ_N may be Coefficient of Restitution
float m_timer = 0; // Start is called before the first frame update
void Start()
{
Mesh mesh = GetComponent<MeshFilter>().mesh;
V = new Vector3[mesh.vertices.Length];
X = mesh.vertices;
Y = mesh.vertices;
OldX = mesh.vertices;
Q = mesh.vertices; //Centerizing Q.
Vector3 c=Vector3.zero;
for(int i=0; i<Q.Length; i++)
c+=Q[i];
c/=Q.Length;
Debug.Log("C: " + c);
for(int i=0; i<Q.Length; i++)
Q[i]-=c; //Get QQ^t ready.
for(int i=0; i<Q.Length; i++)
{
QQt[0, 0]+=Q[i][0]*Q[i][0];
QQt[0, 1]+=Q[i][0]*Q[i][1];
QQt[0, 2]+=Q[i][0]*Q[i][2];
QQt[1, 0]+=Q[i][1]*Q[i][0];
QQt[1, 1]+=Q[i][1]*Q[i][1];
QQt[1, 2]+=Q[i][1]*Q[i][2];
QQt[2, 0]+=Q[i][2]*Q[i][0];
QQt[2, 1]+=Q[i][2]*Q[i][1];
QQt[2, 2]+=Q[i][2]*Q[i][2];
}
QQt[3, 3]=1; for(int i=0; i<X.Length; i++)
V[i][0]=4.0f; Update_Mesh(transform.position, Matrix4x4.Rotate(transform.rotation), 0);
transform.position=Vector3.zero;
transform.rotation=Quaternion.identity;
} Matrix4x4 vector3x1dotvector1x3(Vector3 A, Vector3 B)
{
Matrix4x4 rlt = Matrix4x4.zero;
rlt[3, 3] = 1.0f; rlt[0, 0] = A[0] * B[0];
rlt[0, 1] = A[0] * B[1];
rlt[0, 2] = A[0] * B[2]; rlt[1, 0] = A[1] * B[0];
rlt[1, 1] = A[1] * B[1];
rlt[1, 2] = A[1] * B[2]; rlt[2, 0] = A[2] * B[0];
rlt[2, 1] = A[2] * B[1];
rlt[2, 2] = A[2] * B[2]; return rlt;
} // Polar Decomposition that returns the rotation from F.
Matrix4x4 Get_Rotation(Matrix4x4 F)
{
Matrix4x4 C = Matrix4x4.zero;
for(int ii=0; ii<3; ii++)
for(int jj=0; jj<3; jj++)
for(int kk=0; kk<3; kk++)
C[ii,jj]+=F[kk,ii]*F[kk,jj]; Matrix4x4 C2 = Matrix4x4.zero;
for(int ii=0; ii<3; ii++)
for(int jj=0; jj<3; jj++)
for(int kk=0; kk<3; kk++)
C2[ii,jj]+=C[ii,kk]*C[jj,kk]; float det = F[0,0]*F[1,1]*F[2,2]+
F[0,1]*F[1,2]*F[2,0]+
F[1,0]*F[2,1]*F[0,2]-
F[0,2]*F[1,1]*F[2,0]-
F[0,1]*F[1,0]*F[2,2]-
F[0,0]*F[1,2]*F[2,1]; float I_c = C[0,0]+C[1,1]+C[2,2];
float I_c2 = I_c*I_c;
float II_c = 0.5f*(I_c2-C2[0,0]-C2[1,1]-C2[2,2]);
float III_c = det*det;
float k = I_c2-3*II_c; Matrix4x4 inv_U = Matrix4x4.zero;
if(k<1e-10f)
{
float inv_lambda=1/Mathf.Sqrt(I_c/3);
inv_U[0,0]=inv_lambda;
inv_U[1,1]=inv_lambda;
inv_U[2,2]=inv_lambda;
}
else
{
float l = I_c*(I_c*I_c-4.5f*II_c)+13.5f*III_c;
float k_root = Mathf.Sqrt(k);
float value=l/(k*k_root);
if(value<-1.0f) value=-1.0f;
if(value> 1.0f) value= 1.0f;
float phi = Mathf.Acos(value);
float lambda2=(I_c+2*k_root*Mathf.Cos(phi/3))/3.0f;
float lambda=Mathf.Sqrt(lambda2); float III_u = Mathf.Sqrt(III_c);
if(det<0) III_u=-III_u;
float I_u = lambda + Mathf.Sqrt(-lambda2 + I_c + 2*III_u/lambda);
float II_u=(I_u*I_u-I_c)*0.5f; float inv_rate, factor;
inv_rate=1/(I_u*II_u-III_u);
factor=I_u*III_u*inv_rate; Matrix4x4 U = Matrix4x4.zero;
U[0,0]=factor;
U[1,1]=factor;
U[2,2]=factor; factor=(I_u*I_u-II_u)*inv_rate;
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
U[i,j]+=factor*C[i,j]-inv_rate*C2[i,j]; inv_rate=1/III_u;
factor=II_u*inv_rate;
inv_U[0,0]=factor;
inv_U[1,1]=factor;
inv_U[2,2]=factor; factor=-I_u*inv_rate;
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
inv_U[i,j]+=factor*U[i,j]+inv_rate*C[i,j];
} Matrix4x4 R=Matrix4x4.zero;
for(int ii=0; ii<3; ii++)
for(int jj=0; jj<3; jj++)
for(int kk=0; kk<3; kk++)
R[ii,jj]+=F[ii,kk]*inv_U[kk,jj];
R[3,3]=1;
return R;
} // Update the mesh vertices according to translation c and rotation R.
// It also updates the velocity.
void Update_Mesh(Vector3 c, Matrix4x4 R, float inv_dt)
{
for(int i=0; i<Q.Length; i++)
{
Vector3 x=(Vector3)(R*Q[i])+c; V[i] = (x-X[i])*inv_dt;
X[i] = x;
}
Mesh mesh = GetComponent<MeshFilter>().mesh;
mesh.vertices=X;
} void Collision(float inv_dt)
{
for(int i=0; i<Q.Length; i++)
{
if(Vector3.Dot(X[i] - ground, groundNormal) < 0 && Vector3.Dot(V[i], groundNormal) < 0)// collision with ground
{
Vector3 VN = Vector3.Dot(V[i], groundNormal) * groundNormal;
Vector3 VT = V[i] - VN;
float a = Mathf.Max(0, 1.0f - mu_T * (1.0f + mu_N)) * Vector3.Magnitude(VN) / Vector3.Magnitude(VT);
V[i] = -1.0f * mu_N * VN + 2.0f * a * VT;
}
else if(Vector3.Dot(X[i] - wall, wallNormal) < 0 && Vector3.Dot(V[i], wallNormal) < 0) // collision with wall
{
Vector3 VN = Vector3.Dot(V[i], wallNormal) * wallNormal;
Vector3 VT = V[i] - VN;
float a = Mathf.Max(0, 1.0f - mu_T * (1.0f + mu_N)) * Vector3.Magnitude(VN) / Vector3.Magnitude(VT);
V[i] = -1.0f * mu_N * VN + 2.0f * a * VT;
}
}
} // Update is called once per frame
void Update()
{ if (Input.GetKey("l"))
{
launched = true;
for(int i=0; i<V.Length; i++)
{
V[i] = new Vector3(5.0f, 2.0f, 0.0f);
}
}
if (Input.GetKey("r"))
{
launched = false;
for (int i = 0; i < V.Length; i++)
{
V[i] = new Vector3(4.0f, 0.0f, 0.0f);
} Update_Mesh(new Vector3(0, 0.6f, 0), Matrix4x4.Rotate(transform.rotation), 0);
}
if(!launched)
{
return;
}
//m_timer += Time.time;
//if (m_timer <= 500)
//{
// return;
//}
//else
//{
// m_timer = 0;
//} float dt = 0.015f; //Step 1: run a simple particle system.
for(int i=0; i<V.Length; i++)
{
V[i] = V[i] + G * dt;
V[i] *= linear_decay;
} //Step 2: Perform simple particle collision.
Collision(1/dt); // Step 3: Use shape matching to get new translation c and
// new rotation R. Update the mesh by c and R.
//Shape Matching (translation)
for(int i=0; i<V.Length; i++)
{
Y[i] = X[i] + V[i] * dt;
} // calc c
Vector3 c = new Vector3(0, 0, 0);
for(int i=0; i<V.Length; i++)
{
c += Y[i];
}
c = c / V.Length; // calc A
Matrix4x4 A = Matrix4x4.zero;
A[3, 3] = 1.0f;
for (int i=0; i<V.Length; i++)
{
Matrix4x4 o = vector3x1dotvector1x3(Y[i] - c, Q[i]);
A[0, 0] += o[0, 0];
A[0, 1] += o[0, 1];
A[0, 2] += o[0, 2];
A[1, 0] += o[1, 0];
A[1, 1] += o[1, 1];
A[1, 2] += o[1, 2];
A[2, 0] += o[2, 0];
A[2, 1] += o[2, 1];
A[2, 2] += o[2, 2];
}
A = A * QQt.inverse; //Shape Matching (rotation)
// calc R
Matrix4x4 R = Matrix4x4.zero;
R = Get_Rotation(A); Update_Mesh(c, R, 1/dt); }
}

TRICK

PIPELINE

计算 C (模型质心坐标)

计算 A (通过A计算得到R, 即 旋转矩阵) == 从A得到R. 老师已经提供了.

更新顶点坐标

Trick

在处理碰撞的函数中. 里面的参数是自己调整的参数. 比如 5.0f 逻辑上 μ_T μ_N 都应该是一个小于1的数. 但是, 测试后感觉效果不是特别好. 如果你知道为什么的话, 请留言.

请看完bilibli 4个视屏后开始自己的作业.

参考链接

配置VS 作为 Unity 的配置环境

https://blog.csdn.net/qq_34405576/article/details/105572069

源码参考师弟写出来的, 大部分是抄的嘿嘿~~ 侵权删除.

GAMES 103 动画基础作业1 Shape Matching 浅浅解析的更多相关文章

  1. iOS开发UI篇—核心动画(基础动画)

    转自:http://www.cnblogs.com/wendingding/p/3801157.html 文顶顶 最怕你一生碌碌无为 还安慰自己平凡可贵 iOS开发UI篇—核心动画(基础动画) iOS ...

  2. 【腾讯GAD暑期训练营游戏程序开发】游戏中的动画系统作业

    游戏中的动画系统作业说明文档   一.实现一个动画状态机:至少包含3组大的状态节点

  3. 《Programming WPF》翻译 第8章 1.动画基础

    原文:<Programming WPF>翻译 第8章 1.动画基础 动画包括在一段时间内改变用户界面的某些可见的特征,如它的大小.位置或颜色.你可以做到这一点,非常困难的通过创建一个tim ...

  4. 【2017-04-01】JS字符串的操作、时间日期的操作、函数、事件、动画基础

    一.字符串的操作 1.转大写: s.toLowerCase(); 2.转大写: s.toUpperCase(); 3.字符串的截取: s.substr(3,4);      -从索引3开始截取,截取4 ...

  5. 炫丽的倒计时效果Canvas绘图与动画基础

    前言 想要在自己做的网页中,加入canvas动画效果,但是发现模板各种调整不好,觉得还是要对canvas有所了解,才可以让自己的网页变得狂拽炫酷吊炸天! 一.绘制基础 1 <!DOCTYPE h ...

  6. 动画基础--基于Core Animation(3)

    参考:https://zsisme.gitbooks.io/ios-/content/ 前面的文章动画基础--基于Core Animation(1),动画基础--基于Core Animation(2) ...

  7. 动画基础--基于Core Animation(2)

    参考:https://zsisme.gitbooks.io/ios-/content/ 前面的文章动画基础--基于Core Animation(1)提到了图层的基本概念以及可动画参数几何学等知识. 本 ...

  8. iOS 动画基础总结篇

    iOS 动画基础总结篇   动画的大体分类(个人总结可能有误) 分类.png UIView 动画 属性动画 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 1 ...

  9. HTML5+JavaScript动画基础 完整版 中文pdf扫描版

    <HTML5+JavaScript动画基础>包括了基础知识.基础动画.高级动画.3D动画和其他技术5大部分,分别介绍了动画的基本概念.动画的JavaScript基础.动画中的三角学.渲染技 ...

  10. Expression Blend学习动画基础

    原文:Expression Blend学习动画基础 什么是动画(Animation)? 动画就是时间+换面的组合,画面跟着时间变化.最常见的是flash的动画,还有GIF动态图片. 动画的主要元素 时 ...

随机推荐

  1. SpringBoot3整合SpringSecurity6(一)快速入门

    大家好,我是晓凡. 写在前面 不知道小伙伴们在学SpringSecurity过程中有没有和我一样的经历和烦恼. ①看完一篇文章或者一个教程,感觉学会了.但是一到实际项目中就不知道怎么用: ②被Spri ...

  2. 关于composer报错The openssl extension is required for SSL/TLS protection but is not available问题

    今天使用composer的时候得到了这个错误: The openssl extension is required for SSL/TLS protection but is not availabl ...

  3. SpringIntegrationRamble

    目录 Why SpringIntegration Background Consolidate Architecture ESB service Popular Solutions Getting S ...

  4. Java--Calendar类,Date类的简单使用,日期的格式化

    package demo; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; / ...

  5. 工具 | Hfish

    0x00 简介 HFish是一款社区型免费蜜罐. 下载地址 HFish下载: HFish下载 0x01 功能说明 支持多种蜜罐服务 支持自定义Web蜜罐 支持流量牵引 支持端口扫描感知能力 支持多种告 ...

  6. 代码随想录第十五天 | Leecode 110. 平衡二叉树、257. 二叉树的所有路径、404. 左叶子之和、222. 完全二叉树的节点个数

    Leecode 110. 平衡二叉树 题目描述 给定一个二叉树,判断它是否是 平衡二叉树(是指该树所有节点的左右子树的高度相差不超过 1.) 示例 1: 输入:root = [3,9,20,null, ...

  7. HarmonyOS NEXT开发实战教程--招聘app

    这一周忙到起飞,只能在周末发个文章.今天的内容比较简单,是一个招聘app,适合新手友友参考,大佬们可以直接忽略. 看一下效果图: 这是一个比较常见的应用,大家做这类应用建议大家先分析一下应用和页面的结 ...

  8. ESP32 MQTT对接巴法云平台

    ESP32 MQTT对接巴法云平台 MQTT(Message Queuing Telemetry Transport)是一种轻量级的 发布/订阅(Publish/Subscribe) 消息传输协议,专 ...

  9. JS高级用法:像大神一样玩转JavaScript

    @charset "UTF-8"; .markdown-body { line-height: 1.75; font-weight: 400; font-size: 15px; o ...

  10. 关于I/O与并发

    前言 由于笔者在之前发布的一文玩转NGINX中提到过I/O复用模型,在此另起一篇文章简述相关技术. 什么是I/O I/O输入/输出(Input/Output),分为IO设备和IO接口两个部分. 在PO ...