games101 作业8

差不多过了四个月(一个学期)了,这个学期太忙了,之前一直没有写出作业8,再加上这个学期,太折磨了,几乎就是在荒废时间,暑假在忙保研的事情,其实还有一个营,不过差不多就要确定了吧,于是最终在今天写完了作业8。

同样的,我们来看作业要求:

在 rope.cpp 中, 实现 Rope 类的构造函数。这个构造函数应该可以创建一个新的绳子 (Rope) 对象,该对象从 start 开始,end 结束,包含 num_nodes 个节点。每个结点都有质量,称为质点;质点之间的线段是一个弹簧。通过创建一系列的质点和弹簧,你就可以创建一个像弹簧一样运动的物体。
pinned_nodes 设置结点的索引。这些索引对应结点的固定属性 (pinned attribute) 应该设置为真(他们是静止的)。对于每一个结点,你应该构造一个 Mass对象,并在 Mass 对象的构造函数里设置质量和固定属性。(请仔细阅读代码,确定传递给构造函数的参数)。你应该在连续的两个结点之间创建一个弹簧,设置弹簧两端的结点索引和弹簧系数 k,请检查构造函数的签名以确定传入的参数。
 
这个应该很简单,我们要注意,弹簧的数量比节点的数量多一个,这样就很简单了,简单向量计算即可
 Rope::Rope(Vector2D start, Vector2D end, int num_nodes, float node_mass, float k, vector<int> pinned_nodes)
    {
        // TODO (Part 1): Create a rope starting at `start`, ending at `end`, and containing `num_nodes` nodes.
        for(int i=0;i<num_nodes;i++)
        {
            Vector2D current = start + i*(end-start)/(num_nodes-1);
            Mass*  tmp = new Mass(current,node_mass,false);
            masses.push_back(tmp);
        }
        for(int i=0;i<num_nodes-1;i++)
        {
            Spring* tmp = new  Spring(masses[i],masses[i+1],k);
            springs.push_back(tmp);
        }
//        Comment-in this part when you implement the constructor
        for (auto &i : pinned_nodes) {
            masses[i]->pinned = true;
        }
    }

 

接下来是实现胡克定律和隐式/显式欧拉,这里有一个问题,就是我的显式欧拉似乎一直不稳定,但是隐式欧拉是稳定的

基于物理,注意,走入CGL/include 文件夹,其实我们能看到作业框架引用的一系列函数库,计算向量的模长可以用norm()函数,而计算向量的归一化可以用unit函数,属实节省了不少时间。

注意,显式的欧拉要求我们按照原来的速度算位置,而隐式先让我们算好后面的速度然后计算最终位置

这里最令人难以理解的就是“阻尼”的计算,按照闫神课上讲的,我们应该在Springs循环算每一个阻尼,作业pdf这里没讲明白,其实在论坛上助教指出很简单,就是做一个速度的衰减就行了,具体的讨论可以看这两个帖子

HW8的一些问题 – 计算机图形学与混合现实研讨会 (games-cn.org)

关于作业8的一些问题解答 – 计算机图形学与混合现实研讨会 (games-cn.org)

 

 

 void Rope::simulateEuler(float delta_t, Vector2D gravity)
    {
        for (auto &s : springs)
        {
            // TODO (Part 2): Use Hooke's law to calculate the force on a node
            Vector2D ab = s->m2->position - s->m1->position;
            Vector2D f =  s->k *  (ab.unit()) * (ab.norm() - s->rest_length);
            s->m1->forces += f;
            s->m2->forces -= f;
        }

        for (auto &m : masses)
        {
             float k_d  = 0.1;
            if (!m->pinned)
            {
                // TODO (Part 2): Add the force due to gravity, then compute the new velocity and position
                m->forces += gravity * m->mass;
                // TODO (Part 2): Add global damping
                m->forces += - k_d * m->velocity;
                Vector2D a = m->forces / m->mass;
               /*
                    //explicit  Euler  
                m->position += m->velocity * delta_t;
                m->velocity += a * delta_t;
               */
                   //implicit Euler   
                m->velocity += a * delta_t;
                m->position += m->velocity * delta_t;
            }
            // Reset all forces on each mass
            m->forces = Vector2D(0, 0);
        
       }
    }

 

 

 

 然后是最后的显示Verlet方法,注意我们这里会用到mass中的last_position参数,用于保存X(t-1),其实这里很简单,就是把前面的一部分复制过来,然后按照作业要求写出最关键的那一行带阻尼的公式就行,注意用last_position进行记忆原先的值即可

 void Rope::simulateVerlet(float delta_t, Vector2D gravity)
    {
        for (auto &s : springs)
        {
            // TODO (Part 3): Simulate one timestep of the rope using explicit Verlet (solving constraints)
            Vector2D ab = s->m2->position - s->m1->position;
            Vector2D f = s->k *  (ab.unit()) * (ab.norm() - s->rest_length);
            s->m1->forces += f;
            s->m2->forces -= f;
        }

        for (auto &m : masses)
        {
            if (!m->pinned)
            {
                m->forces += gravity * m->mass;
                Vector2D a = m->forces / m->mass;

                // TODO (Part 3.1): Set the new position of the rope mass
                Vector2D temp = m->position;
                // TODO (Part 4): Add global Verlet damping
                double  damping_factor = 0.00005;
// 核心公式,带阻尼的计算 m
->position = m->position + (1 - damping_factor) * (m->position - m->last_position) + a * delta_t *delta_t;
// 用last_position记忆原先的位置 m
->last_position = temp; } m->forces = Vector2D(0,0); } } }

 

 可以看一下最终的效果

posted @ 2021-07-26 00:19  coolwx  阅读(1630)  评论(0编辑  收藏  举报