Games 103 作业一

news2024/11/18 19:37:21

Games 103 作业一

整个作业一的内容其实就是要自己动手实现一遍ImpulseShape Matching这两个方法。作业中给的示例场景如下:

Games 103 作业一1

场景中有个兔子的刚体,我们要模拟的就是给兔子一个初始的速度,让其在重力的影响下,与两堵墙发生碰撞的效果。

先看Impulse方法的实现,实现思路就是主要参考PPT中第28页:

Games 103 作业一2

首先,我们需要对兔子mesh中的所有顶点进行遍历,找到与墙平面发生碰撞的所有顶点,检查任意顶点是否与墙平面发生碰撞也很简单,就是计算点到平面的距离,若为负值即发生碰撞,也就是PPT中的 ϕ ( x i ) < 0 \phi(\textbf{x}_i) < 0 ϕ(xi)<0

Mesh mesh = GetComponent<MeshFilter>().mesh;
Vector3[] vertices = mesh.vertices;

Vector3 avg = Vector3.zero;
int num = 0;
for(int i = 0; i < vertices.Length; i++)
{
    Vector3 vert = transform.TransformPoint(vertices[i]);
    if(Vector3.Dot(vert - P, N) < 0)
    {
        avg += vert;
        num++;
    }
}

如果这里得到的num为0,说明所有点都没有和平面发生碰撞,也就不必再继续计算了。下一步,我们计算发生碰撞的点的平均值,作为 x i \textbf{x}_i xi,而 R r i \textbf{R}\textbf{r}_i Rri其实就是模型中心到这个点的向量:

Games 103 作业一3

那么我们就可以得到 v i \textbf{v}_i vi,根据速度的方向来判断是否发生碰撞:

avg /= num;

Vector3 rri = avg - transform.position;
Vector3 vi = v + Vector3.Cross(w, rri);
float dot = Vector3.Dot(vi, N);
if(dot >= 0)
{
    return;
}

如果发生碰撞,则需要根据PPT中的公式,更新 v i \textbf{v}_i vi

Vector3 vni = dot * N;
Vector3 vti = vi - vni;
float a = Mathf.Max(1 - u_t * (1 + u_n) * Vector3.Magnitude(vni) / Vector3.Magnitude(vti), 0);
vni = -u_n * vni;
vti = a * vti;
Vector3 vinew = vni + vti;

有了新的 v i \textbf{v}_i vi之后,就可以根据它计算出当前的冲量 j \textbf{j} j

Matrix4x4 inv = Matrix4x4.Inverse(I_ref);
Matrix4x4 k1 = Matrix4x4.identity;
for(int i = 0; i < 4; i++)
{
	k1[i, i] = 1 / mass;
}
Matrix4x4 k2 = Get_Cross_Matrix(rri) * inv * Get_Cross_Matrix(rri);
Matrix4x4 k = new Matrix4x4();
for(int i = 0; i < 4; i++)
{
    for(int j = 0; j < 4; j++)
    {
        k[i, j] = k1[i, j] - k2[i, j];
    }
}

Vector3 J = Matrix4x4.Inverse(k) * (vinew - vi);

进而可以更新刚体的速度 v \textbf{v} v和角速度 w \textbf{w} w

v = v + J / mass;
Vector3 tmp1 = Vector3.Cross(rri, J);
Vector4 tmp2 = new Vector4(tmp1.x, tmp1.y, tmp1.z, 0);
Vector3 tmp3 = inv * tmp2;
w = w + new Vector3(tmp3.x, tmp3.y, tmp3.z);

最终就得到了下一时刻刚体的位置和旋转。实现的效果如下:

Games 103 作业一4

接下来就是Shape Matching方法了,它的原理就是让每个顶点先分别自由地计算各自的速度和位置,然后再根据刚体的约束,对顶点进行调整,得到每个顶点最终的速度和位置。实现思路也主要参考PPT中第39页:

Games 103 作业一5

每个顶点与平面发生碰撞的逻辑依旧可以用Impulse的方法来处理,只不过这里只需要计算出每个顶点碰撞后新的速度 v i \textbf{v}_i vi即可:

void Collision(float inv_dt)
{
    for(int i = 0; i < Y.Length; i++)
    {
        Collision_Impulse(i, new Vector3(0, 0.01f, 0), new Vector3(0, 1, 0));
        Collision_Impulse(i, new Vector3(2, 0, 0), new Vector3(-1, 0, 0));
    }
}

更新完位置后,需要计算当前时刻下刚体的中心,以及新的旋转:

Vector3 c=Vector3.zero;
for(int i=0; i<Y.Length; i++)
    c+=Y[i];
c/=Y.Length;
//Shape Matching (translation)
Matrix4x4 A = Matrix4x4.zero;
for(int i=0; i<Y.Length; i++)
{
    Vector3 yic = Y[i] - c;
    A[0, 0]+=yic[0]*Q[i][0];
    A[0, 1]+=yic[0]*Q[i][1];
    A[0, 2]+=yic[0]*Q[i][2];
    A[1, 0]+=yic[1]*Q[i][0];
    A[1, 1]+=yic[1]*Q[i][1];
    A[1, 2]+=yic[1]*Q[i][2];
    A[2, 0]+=yic[2]*Q[i][0];
    A[2, 1]+=yic[2]*Q[i][1];
    A[2, 2]+=yic[2]*Q[i][2];
}
A[3, 3]=1;
A *= Matrix4x4.Inverse(QQt);
//Shape Matching (rotation)
Matrix4x4 R = Get_Rotation(A);

然后,我们再反过来,根据当前的约束去计算每个顶点真正的位置,再和上一时刻的顶点的位置做差,就能得到每个顶点当前时刻的速度了:

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;
}

最后运行的效果如下:

Games 103 作业一6

如果你觉得我的文章有帮助,欢迎关注我的微信公众号 我是真的想做游戏啊

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/898762.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

嵌入式开发中的抽象、封装与继承

嵌入式开发中的抽象、封装与继承 ## 1 何从实现&#xff1f; OOP 是 CPP 的显著特征&#xff0c;尽管它是一种多重范式的语言 第一部分谈的是产品的实现&#xff08;implement&#xff09;而非产品的设计&#xff0c;因为对于个人开发者而言&#xff0c;往往是知道如何实现产…

港科夜闻|香港科大校长叶玉如教授、香港科大(广州)校长倪明选教授等两校领导共同出席香港科大(广州)首批本科新生见面会...

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大校长叶玉如教授、香港科大(广州)校长倪明选教授等两校领导共同出席香港科大(广州)首批本科新生见面会。8月16日&#xff0c;香港科大(广州)首批本科新生参加了一次具有特殊意义的见面会。香港科大、香港科大(广州…

菜单中的类似iOS中开关的样式

背景是我们有需求&#xff0c;做类似ios中开关的按钮。github上有一些开源项目&#xff0c;比如 SwitchButton&#xff0c; 但是这个项目中提供了很多选项&#xff0c;并且实际使用中会出现一些奇怪的问题。 我调整了下代码&#xff0c;把无关的功能都给删了&#xff0c;保留核…

Unsafe Filedownload

文件下载功能在很多web系统上都会出现&#xff0c;一般我们当点击下载链接&#xff0c;便会向后台发送一个下载请求&#xff0c;一般这个请求会包含一个需要下载的文件名称&#xff0c;后台在收到请求后会开始执行下载代码&#xff0c;将该文件名对应的文件response给浏览器&am…

XDR解决方案正式发布

面对日益严峻的网络安全形势&#xff0c;为了增强安全防护能力&#xff0c;不同单位经常不定期举行以真实网络目标为对象的攻防实战演练&#xff0c;旨在发现、暴露和解决安全问题&#xff0c;检验各个企业单位的网络安全防护水平和应急处置能力。 作为攻防实战防守方的蓝队&am…

WebStrom 前端项目Debug

1. 正常启动前端项目 2. 配置webStrom的JavaScript Debugger 点击Edit Configurations添加avaScript Debug填写URL 为项目启动路径配置要Debug的浏览器-remote-allow-origins* &#xff08;最重要&#xff0c;否则唤起的是一个about:blank空白页面&#xff09; 3. 启动Debug模…

[ MySQL ] — 基础增删查改的使用

目录 表的增删查改 Create 单行数据 全列插入 多行数据 全列插入 多行数据 指定列插入 不存在插入存在则更新 替换 Retrieve SELECT 列 全列查询 指定列查询 查询字段为表达式 为查询结果指定别名 结果去重 WHERE 条件 结果排序 筛选结果分页 Update De…

GPT系列总结

1.GPT1 无监督预训练有监督的子任务finetuning https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf 1.1 Unsupervised pre-training &#xff08;1&#xff09;通过一个窗口的输入得到下一个token在目标token上的一个概率分布…

all in one之安装pve(第一章)

第一章 安装PVE PVE安装 pverufusultraISO下载地址下载地址下载地址 因为我使用的是SD卡存储&#xff0c;尝试rufus安装失败&#xff0c;建议使用 ultraISO进行镜像写入。 U盘推荐4G往上。 下载pve 我下载的pve版本是7.4 ultraISO 把镜像写入u盘 下载完成后需要把镜像文件…

小米分享 | 解密面试题:网易面试如何回答“创建线程有哪几种方式?”

大家好&#xff0c;我是你们的小米&#xff01;今天要和大家一起探讨一个在技术面试中常见的问题&#xff1a;创建线程有哪几种方式&#xff1f;这可是个经典面试题哦&#xff01;不过别担心&#xff0c;小米在这里为你详细解析&#xff0c;帮你轻松应对&#xff0c;让你在面试…

【Unity每日一记】关于五种范围检测方法的总结

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

Hlang--用Python写个编程语言-变量的实现

文章目录 前言语法规则表示次幂实现变量实现优先级实现步骤解析关键字语法解析解释器总结前言 先前的话,我们终于是把我们整个架子搭起来了,这里重复一下我们的流程,那就是,首先,我们通过解析文本,然后呢遍历文本当中的我们定义的合法关键字,然后呢,把他们封装为一个T…

基于Redis的Geo实现附近商铺搜索(含源码)

微信公众号访问地址&#xff1a;基于Redis的Geo实现附近商铺搜索(含源码) 推荐文章&#xff1a; 1、springBoot对接kafka,批量、并发、异步获取消息,并动态、批量插入库表; 2、SpringBoot用线程池ThreadPoolTaskExecutor异步处理百万级数据; 3、基于Redis的Geo实现附近商铺搜索…

34.Netty源码之Netty如何处理网络请求

highlight: arduino-light 通过前面两节源码课程的学习&#xff0c;我们知道 Netty 在服务端启动时会为创建 NioServerSocketChannel&#xff0c;当客户端新连接接入时又会创建 NioSocketChannel&#xff0c;不管是服务端还是客户端 Channel&#xff0c;在创建时都会初始化自己…

Azure文件共享

什么是Azure文件共享 Azure文件共享是一种在云中存储和访问文件的服务。它允许用户在不同的计算机、虚拟机和服务之间共享数据&#xff0c;并在应用程序中进行访问、修改和管理。 Azure文件共享可以用于各种用途&#xff0c;例如&#xff1a; 共享文件资源给多个虚拟机或服务…

P6685 可持久化动态仙人掌的直径问题

思路1&#xff1a;二分快速幂 #include<bits/stdc.h> using namespace std; #define int long long int n,m; bool check(int a,int b){int ans1;while(b){if(a>n)return false;if(b&1)ans*a;if(ans>n)return false;aa*a;b>>1;}return ans<n; } voi…

STM32CubeMx之freeRTOS定时器使用

需要修改定时器时钟 xTimerChangePeriod(tim1Handle,500,200);//发送队列等待时间 第二个参数为修改的ms xTimerStart(tim1Handle,100);//开启定时器 xTimerStop(tim1Handle,100);//关闭定时器 一定注意定时器任务优先级 要大一点 不然会使用不了

【GaussDB】 SQL 篇

建表语句 表的分类 普通的建表语句 复制表内容 只复制表结构 create table 新表名(like 源表名 including all); 如果希望注释被复制的话要指定including comments 复制索引、主键约束和唯一约束&#xff0c;那么需要指定including indexes including constraints &#xf…

AI 媒人:为什么图形神经网络比 MLP 更好?

一、说明 G拉夫神经网络&#xff08;GNN&#xff09;&#xff01;想象他们是人工智能世界的媒人&#xff0c;通过探索他们的联系&#xff0c;不知疲倦地帮助数据点找到朋友和人气。数字派对上的终极僚机。 现在&#xff0c;为什么这些GNN如此重要&#xff0c;你问&#xff1f;好…

铺设道路(c++题解)

题目背景 NOIP2018 提高组 D1T1 题目描述 春春是一名道路工程师&#xff0c;负责铺设一条长度为 n 的道路。 铺设道路的主要工作是填平下陷的地表。整段道路可以看作是 n 块首尾相连的区域&#xff0c;一开始&#xff0c;第 i 块区域下陷的深度为 di​ 。 春春每天可以选择…