作业8
题目:
模拟绳子动画,包括基于物理的,和非物理的,应该修改的函数是:rope.cpp 中的void Rope::simulateEuler(... Rope::rope(...),,void Rope::simulateVerlet(...)
代码框架:
main:负责接收命令行参数,通过getopt捕获参数设置AppConfig的数据-》创建Application,设置渲染器
-
int getopt(int argc,char * const argv[ ],const char * optstring);用来分析命令行参数
-
参数argc和argv分别代表参数个数和内容,跟main( )函数的命令行参数是一样的。
-
参数 optstring为选项字符串
-
单个字符,表示选项
-
单个字符后接一个冒号:表示该选项后必须跟一个参数
-
单个字符后跟两个冒号,表示该选项后可以跟一个参数,也可以不跟。
-
-
全域变量optarg指向当前选项参数(如果有)的指针。
-
CGL:命名空间,包含应用层一下所有模块
application:应用程序
-
AppConfig类,负责从命令行接收信息,mass质点的质量,ks弹簧劲度系数,gravity重力,steps_per_frame每帧仿真步长数
-
Application类继承CGL库中的Renderer
-
初始化,调用rope的构造函数
-
渲染,通过opengl库:渲染点(质点),线(弹簧)
-
void Application::render() {//Simulation loopsfor (int i = 0; i < config.steps_per_frame; i++) {/* 每帧仿真步长数 *//* 对两个绳子更新这一帧的位置 */ropeEuler->simulateEuler(1 / config.steps_per_frame, config.gravity);ropeVerlet->simulateVerlet(1 / config.steps_per_frame, config.gravity);}// Rendering ropesRope *rope;/* 分别两个绳子,并设置颜色,和当前绳子*/for (int i = 0; i < 2; i++) {if (i == 0) {glColor3f(0.0, 0.0, 1.0);rope = ropeEuler;} else {glColor3f(0.0, 1.0, 0.0);rope = ropeVerlet;}/* 绘制质点 */glBegin(GL_POINTS);for (auto &m : rope->masses) {Vector2D p = m->position;glVertex2d(p.x, p.y);}glEnd();/* 绘制弹簧 */glBegin(GL_LINES);for (auto &s : rope->springs) {Vector2D p1 = s->m1->position;Vector2D p2 = s->m2->position;glVertex2d(p1.x, p1.y);glVertex2d(p2.x, p2.y);}glEnd();/* 提交缓冲区到前台 */glFlush();}
}
rope:绳子类,包括质点数组,弹簧数组,simulateEuler基于物理的仿真,simulateVerlet非物理的仿真
mass:质点类,包含一个质点,质量,pinned是否是固定的,开始位置,速度,受力等
spring:弹簧类,包括一个弹簧,2个质点,长度,劲度系数k等
解:
首先安装库
sudo apt i n s t a l l l i b g l u 1 −mesa−dev f r e e g l u t 3 −dev \\
mesa−common−dev
sudo apt i n s t a l l xorg−dev #会自 动 安装 l i b f r e e t y p e 6 −dev
创建绳子
在构造函数中,遍历每个质点,调用mass:类和spring类的构造,并存放到rope的数组中,并且根据参数值,设置mass:对象和spring对象的属性
Vector2D step = (end - start) / (num_nodes - 1);
for(int i = 0; i < num_nodes; i++){masses.push_back(new Mass(start + step * i, node_mass, true));if(i){springs.push_back(new Spring(masses[i-1], masses[i], k));masses[i]->pinned = false;}
}
simulateEuler()
首先遍历绳子的每个弹簧,根据胡可定律计算受到的力,包括ab质点的相互作用力,fr摩擦力,以及空气阻力,带入公式就好
然后遍历每个质点,如果非固定属性,那么根据首先根据f = ma 计算加速度,再根据欧拉方法计算质点的这一步长的位置,+=是上一步长的位置 + 这一步长的增量
for (auto &s : springs)
{float length = (s->m2->position - s->m1->position).norm();Vector2D dis = s->m2->position - s->m1->position;Vector2D force = s->k * (length - s->rest_length) * dis / length;s->m1->forces += force;s->m2->forces -= force;// dampingVector2D reve = s->m2->velocity - s->m1->velocity;Vector2D force1 = 0.05 * (reve.x * dis.x + reve.y * dis.y) * dis / length;s->m1->forces += force1;s->m2->forces -= force1;// air dampings->m1->forces -= 0.005 * s->m1->velocity;s->m2->forces -= 0.005 * s->m2->velocity;for (auto &m : masses)
{if (!m->pinned){m->forces += gravity;m->velocity += m->forces / m->mass * delta_t;m->position += m->velocity * delta_t;m->forces = Vector2D(0, 0);
}
simulateVerlet()
作业告诉了这个公式, 带入就好
for (auto &s : springs)
{float length = (s->m2->position - s->m1->position).norm();Vector2D dis = s->m2->position - s->m1->position;Vector2D force = s->k * (length - s->rest_length) * dis / length;s->m1->forces += force;s->m2->forces -= force;
}
for (auto &m : masses)
{if (!m->pinned){Vector2D temp_position = m->position;m->forces += gravity;Vector2D pos = m->position;m->position += (1 - 0.00005) * (m->position - m->last_position) + m->forces / m->mass * delta_t * delta_t;m->last_position = pos;}m->forces = Vector2D(0, 0);
}