• Games 103 作业二


    Games 103 作业二

    作业二其实就是要使用隐式积分和PBD两种方式来实现布料求解。难度相对于作业一来说要简单一些,在文档中基本把步骤都写清楚了。主要逻辑首先参考Lecture 05 PPT的第18页:

    Games 103 作业二1

    然后我们按照文档的步骤一步一步地来。注意0号顶点和20号顶点是不参与更新的,它们相当于就是定死了位置。第一步是初始化,这个很简单:

    for (int i = 0; i < V.Length; i++)
    {
        if (!Skip_Update(i))
        {
            V[i] *= damping;
        }
    }
    for(int i = 0; i < X.Length; i++)
    {
        if (!Skip_Update(i))
        {
            X_hat[i] = X[i] + V[i] * t;
            X[i] = X_hat[i];
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    第二步就是计算梯度。这里的梯度就是PPT里的
    ∇ F ( x ( k ) ) = 1 Δ t 2 M ( x ( k ) − x [ 0 ] − Δ t 2 v [ 0 ] ) − f ( x ( k ) ) \nabla F(\textbf{x}^{(k)}) = \dfrac{1}{\Delta t^2} \textbf{M} (\textbf{x}^{(k)} - \textbf{x}^{[0]} - \Delta t^2 \textbf{v}^{[0]}) - \textbf{f} (\textbf{x}^{(k)}) F(x(k))=Δt21M(x(k)x[0]Δt2v[0])f(x(k))
    这里的f就是重力和弹簧间的弹力。重力是个常量好办,弹力的计算需要遍历所有的边,找到边的两个顶点,分别进行计算,参考PPT的第11页:

    Games 103 作业二2

    void Get_Gradient(Vector3[] X, Vector3[] X_hat, float t, Vector3[] G)
    {
        //Momentum and Gravity.
        for (int i = 0; i < G.Length; i++)
        {
            if (!Skip_Update(i))
            {
                G[i] = mass * (X[i] - X_hat[i]) / (t * t) - mass * gravity;
            }
        }
    
        //Spring Force.
        for (int e = 0; e < L.Length; e++)
        {
            int i = E[e * 2 + 0];
            int j = E[e * 2 + 1];
            float x = Vector3.Distance(X[i], X[j]);
            Vector3 f = spring_k * (1 - L[e] / x) * (X[i] - X[j]);
    
            if (!Skip_Update(i))
            {
                G[i] += f;
            }
    
            if (!Skip_Update(j))
            {
                G[j] -= f;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    然后需要计算:
    ∂ 2 F ( x ( k ) ) ∂ x 2 = 1 Δ t 2 M + H ( x ( k ) ) \dfrac{\partial^2F(\textbf{x}^{(k)})}{\partial\textbf{x}^2} = \dfrac{1}{\Delta t^2}\textbf{M} + \textbf{H}(\textbf{x}^{(k)}) x22F(x(k))=Δt21M+H(x(k))
    作业文档中给了近似求解的方法,我们就不用算 H \textbf{H} H了。我们使用Chebyshev加速牛顿法迭代,可以参考PPT中第26页:

    Games 103 作业二3

    作业中是固定的32次迭代次数,这里的break判断就可以省略掉;另外,x的更新直接使用作业里的公式即可:

    for(int k=0; k<32; k++)
    {
        Get_Gradient(X, X_hat, t, G);
    
        if(k == 0)
        {
            omega = 1.0f;
        }
        else if(k == 1)
        {
            omega = 2.0f / (2.0f - rho * rho);
        }
        else
        {
            omega = 4.0f / (4.0f - rho * rho * omega);
        }
        
        //Update X by gradient.
        for(int i = 0; i < X.Length; i++)
        {
            if (!Skip_Update(i))
            {
                Vector3 old = X[i];
                X[i] = omega * (X[i] - 1 / (mass / (t * t) + 4 * spring_k) * G[i]) + (1 - omega) * last_X[i];
                last_X[i] = old;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    迭代完别忘记更新下V,这里要使用+=,因为一开始算 x ~ \widetilde{x} x 的时候加过v了:

    for(int i = 0; i < X.Length; i++)
    {
        if (!Skip_Update(i))
        {
            V[i] += (X[i] - X_hat[i]) / t;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    最后的碰撞检测很简单,算一下点到球心的距离,如果小于半径就说明发生碰撞:

    void Collision_Handling()
    {
        Mesh mesh = GetComponent ().mesh;
        Vector3[] X = mesh.vertices;
    
        //Handle colllision.
        Vector3 c = sphere.transform.position;
        for(int i = 0; i < X.Length; i++)
        {
            if(!Skip_Update(i))
            {
                float d = Vector3.Distance(X[i], c);
                if (d < r)
                {
                    V[i] = V[i] + 1 / t * (c + r * (X[i] - c) / d - X[i]);
                    X[i] = c + r * (X[i] - c) / d;
                }
            }
        }
    
        mesh.vertices = X;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    最后效果如下:

    Games 103 作业二4

    然后我们再看下PBD的实现。第一步就是让每个顶点自由更新:

    for(int i=0; i
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    接下来,通过若干次迭代施加约束,这里可以参考Lecture 06 PPT的第10页:

    Games 103 作业二5

    作业里 α \alpha α取的0.2:

    void Strain_Limiting()
    {
        Mesh mesh = GetComponent ().mesh;
        Vector3[] vertices = mesh.vertices;
    
        //Apply PBD here.
        //...
        Vector3[] sum_X = new Vector3[vertices.Length];
        int[] sum_N = new int[vertices.Length];
    
        for (int e = 0; e < L.Length; e++)
        {
            int i = E[e * 2 + 0];
            int j = E[e * 2 + 1];
            float x = Vector3.Distance(vertices[i], vertices[j]);
            Vector3 f = L[e] * (vertices[i] - vertices[j]) / x;
    
            sum_X[i] += 0.5f * (vertices[i] + vertices[j] + f);
            sum_N[i]++;
            sum_X[j] += 0.5f * (vertices[i] + vertices[j] - f);
            sum_N[j]++;
        }
    
        for(int i = 0; i < V.Length; i++)
        {
            if(i == 0 || i == 20)	continue;
            Vector3 f = (0.2f * vertices[i] + sum_X[i]) / (0.2f + sum_N[i]);
            V[i] += 1 / t * (f - vertices[i]);
            vertices[i] = f;
        }
    
        mesh.vertices = vertices;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    最后效果如下:

    Games 103 作业二6

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

  • 相关阅读:
    如何将转换器应用于时序模型
    网络——TCP拥塞控制
    webpack5 Preload / Prefetch解决按需求加载速度
    安装fabricmanager解决print(torch.cuda.is_available())报错NumCudaDevices()
    前端工程化精讲第六课 团队工具:如何利用云开发提升团队开发效率?
    opencv_模板匹配
    1787_函数指针的使用
    宇宙采集器 淘宝商家电话采集爬虫分享
    edgexfoundry device-sdk-c编译过程记录
    dubbo
  • 原文地址:https://blog.csdn.net/weixin_45776473/article/details/134090564