我需要在布料的模拟中实现风力的简单效果。我的布料由使用弹簧连接的 10x10 个顶点(cloth_vertices 数组中给出的 100 个索引)制成。弹簧定义如下:
function initMassSpringSystem() {
// adding springs
for (let i = 0; i < cloth_size - 1; i++) {
for (let j = 0; j < cloth_size - 1; j++) {
let top = i * cloth_size + j;
// vertical 1
spring_start.push(top);
spring_end.push(top + cloth_size);
spring_rest.push(1.0 / (cloth_size - 1));
// horizontal 1
spring_start.push(top);
spring_end.push(top + 1);
spring_rest.push(1.0 / (cloth_size - 1));
// vertical 2
spring_start.push(top + 1);
spring_end.push(top + 1 + cloth_size);
spring_rest.push(1.0 / (cloth_size - 1));
// horizontal 1
spring_start.push(top + cloth_size);
spring_end.push(top + 1 + cloth_size);
spring_rest.push(1.0 / (cloth_size - 1));
// diagonal 1
spring_start.push(top);
spring_end.push(top + 1 + cloth_size);
spring_rest.push(Math.sqrt(2) * 1.0 / (cloth_size - 1));
// diagonal 2
spring_start.push(top + 1);
spring_end.push(top + cloth_size);
spring_rest.push(Math.sqrt(2) * 1.0 / (cloth_size - 1));
}
}
// initializing velocities and forces
for (i = 0; i < cloth_size * cloth_size; i++) {
v.push(vec3.fromValues(0.0, 0.0, 0.0));
f.push(vec3.fromValues(0.0, 0.0, 0.0));
}
time = Date.now();
}
在我的函数 updateCloth() 中,我已经实现了重力、弹簧和阻尼力,它们可以正常工作,但现在的问题是应用风效果:
function updateCloth() {
// ------------ Assignment ------------
// You need to fill in the gaps in this function
// initializing forces for every particle with gravity and any external forces
for (i = 0; i < cloth_size * cloth_size; i++) {
// gravity act on y direction. All forces are recalculated at each time stamp
f[i][1] = - (mass * 9.8665);
}
// computing the forces exetrted by every spring and adding them to the forces acting on particles
for (i = 0; i < spring_start.length; i++) {
let p = spring_start[i]; // index of the particle/vertex which corresponds to one end of the spring
let q = spring_end[i]; // index of the particle/vertex which corresponds to one end of the spring
// positions of the two ends of the spring
let x_p = vec3.fromValues(cloth_vertices[3 * p], cloth_vertices[3 * p + 1], cloth_vertices[3 * p + 2]);
let x_q = vec3.fromValues(cloth_vertices[3 * q], cloth_vertices[3 * q + 1], cloth_vertices[3 * q + 2]);
// Compute forces exert by the spring and the damping forces
// Use the computed forces to update f[p] and f[q], i.e., accumulated forces which act on the particles
// damping force
let empty = vec3.fromValues(0, 0, 0);
let e = vec3.fromValues(0,0,0);
vec3.sub(e,x_q, x_p);
let len_1 = vec3.distance(x_q,x_p);
let c = vec3.fromValues(0, 0, 0);
vec3.normalize(c,e);
let b1 = vec3.fromValues(0,0,0);
vec3.sub(b1,v[q], v[p]);
vec3.divide(b1, b1, vec3.fromValues(spring_rest[i], spring_rest[i], spring_rest[i]));
let b2 = c;
let b = vec3.dot(b1, b2);
let damping_force = damping * b * c[1];
// hooke's law
let second = (len_1/spring_rest[i])-1;
let third = c[1];
let hooke_law = k * second * third;
// for f[p] y add forces, while subtract for [q] y because the force is in the opposite direction
f[p][1] = f[p][1] + hooke_law + damping_force;
f[q][1] = f[q][1] - hooke_law - damping_force;
// WIND
// take delta time
const end_time = Date.now();
const time_elapsed = end_time - time;
// calculate wind force using a sinusoidal function (such that it oscillates)
const wind = Math.sin(2 * Math.sin(time_elapsed)) + Math.sin(3.14 * Math.sin(time_elapsed));
f[p][0] = wind;
f[q][0] = -wind;
}
// updateing position an velocities of the particles based on forces and masses
for (let i = 0; i < cloth_size * cloth_size; i++) {
// fixed point to avoid cloth falling forever
if ( i === 0 || i === cloth_size - 1) {
// velocity of i-th particle
v[i][0] = 0;
v[i][1] = 0;
v[i][2] = 0;
// position of i-th particle
cloth_vertices[3 * i] = cloth_vertices[3 * i];
cloth_vertices[3 * i + 1] = cloth_vertices[3 * i + 1];
cloth_vertices[3 * i + 2] = cloth_vertices[3 * i + 2];
}
else {
// Here update the velocity and position of every particle
// velocity of i-th particle
v[i][1] = v[i][1] + (deltaT * (f[i][1] / mass));
v[i][2] = 0;
// wind
v[i][0] = v[i][0] + (deltaT * (f[i][0] / mass));
// console.log(v[i][0]);
// position of i-th particle
cloth_vertices[3*i + 1] = cloth_vertices[3*i + 1] + (deltaT * v[i][1]);
// wind
cloth_vertices[3*i+2] = cloth_vertices[3*i+2] + (deltaT * v[i][0]);
}
}
// The three lines below will make sure that the buffer on the GPU,
// which stores the positions of particles, will be updated.
gl.bindBuffer(gl.ARRAY_BUFFER, clothVertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cloth_vertices), gl.DYNAMIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
}
该函数被多次调用以对另一个 run() 方法产生动画效果。我读到风的影响取决于时间变量,然后我取了整个函数执行之前(在调用 updateCloth() 之前定义的时间变量)和每次调用它之间的差异。然后我使用了一个简单的方程找到在我称之为风的互联网上,它允许有一个在负值和正值之间振荡的小值(~-2 / ~+2)。我将此力施加到 f[p],其中 p 是开始弹簧的顶点的索引,我将它的倒数施加到结束弹簧的 f[q](我输入负值,因为我知道在弹簧中一个顶点的力与另一个顶点的力相反,但我不确定这个想法是否也适用于风)。我只在 x 值上施加了这个力(实际上我有 f[p][0])以便于计算,但我认为它必须应用于所有三个方向(我有一个 3D 模拟,然后是 x,y ,z)。结果是布料的一半无限地朝向一个方向,一半朝向另一个方向。力值和速度都正确振荡,但问题是顶点的位置继续增加,有些是正值,有些是负值。我不知道如何获得增加的风的效果,但直到一定值,然后保持不变。我读到它的值取决于顶点的位置(我将布料的左右角固定为不会飞走,然后我想风的效果必须在底部更大布),但我没有
在没有风的情况下,我的布料可以想象如下:
在应用我错误的风效果时,它的行为方式如下:
我希望我提供了所有信息,否则请不要犹豫。