cpu_sph.c

来自「游戏编程精粹6第中关于粒子的实时流体仿真系统,对入门的游戏开发者很有帮助.」· C语言 代码 · 共 741 行 · 第 1/2 页

C
741
字号
				vec3_sub(&vdiff, &VEL(nindex), &VEL(i));

/*
				if ((i < sph->n_rigidp[0]) || (nindex < sph->n_rigidp[0]))
				vec3_scale(&vdiff, 0.0f*sph->viscosity*sph->lap_vis_coef, &vdiff);
				else vec3_scale(&vdiff, sph->viscosity*sph->lap_vis_coef, &vdiff);
				*/
vec3_scale(&vdiff, sph->viscosity*sph->lap_vis_coef, &vdiff);

				vec3_add(&force, &force, &vdiff);


				vec3_scale(&force, h_r*sph->density[i]*sph->density[nindex], &force);

				// Apply force
				vec3_scaleadd(&ACC(i), &ACC(i), sph->mass[nindex], &force);
				vec3_scaleadd(&ACC(nindex), &ACC(nindex), -sph->mass[i], &force);

			}
		}

}


_inline void compute_col(vector3* p, vector3* col,
						 const vector3* vel, const vector3* n, 
						 float diff, float stiff, float damp)
{
	float v0;
	float reverse;

	v0 = vec3_dot(n, vel);
#ifdef PUSHOUT
	//mat4_mulvec3(&n_w, &mat_col, &n);
	vec3_scaleadd(p, p, diff, n);
#endif
#ifdef REFLECT_VEL
	vec3_scaleadd(col, col, -1.9*v0, n);
#else
	reverse = stiff*diff - damp*v0;

	vec3_scaleadd(col, col, reverse, n);
#endif
}
/**
 * col is ref_v if REFLECT_VEL is defined, col_force if REFLECT_VEL is not defined
 */


_inline void cpu_sph_glass_collision(vector3* p, vector3* col, const vector3* vel,
									 const matrix4* mat, const matrix4* mat_inv, 
									 float radius, float stiff, float damp)
{
	float GLASS_R = 0.05f;
	//		float GLASS_R = 0.045;
	float GLASS_BOTTOM = -0.08f;
#ifdef POOR_WATER
	float GLASS_TOP = 0.04f;
#else
	float GLASS_TOP = 0.06f;
	//float GLASS_TOP = 0.18;
	//float GLASS_TOP = 0.26;
#endif
	float GLASS_THICKNESS = 0.01f;

	vector3 p_col;
	vector3 n;
	float diff; /** Distance between object and fluid particle **/

	mat4_mulvec3(&p_col, mat_inv, p);

	diff =
        2.0f*radius - (GLASS_R - (float)sqrt(p_col.x*p_col.x + p_col.y*p_col.y));

	if (((diff < 8.0f*radius) && (diff > EPSILON)) && (p_col.z < GLASS_TOP))
	{
		vec3_set(&n, -p_col.x, -p_col.y, 0.0f);
		vec3_normalize(&n, &n);

		mat4_mulvec3_as_mat3(&n, mat, &n);
		compute_col(p, col, vel, &n, diff, stiff, damp);
	}

	diff = 2.0f*radius - (p_col.z - GLASS_BOTTOM);

	if (diff > EPSILON)
	{
		vec3_set(&n, 0.0f, 0.0f, 1.0f);

		mat4_mulvec3_as_mat3(&n, mat, &n);
		compute_col(p, col, vel, &n, diff, stiff, damp);
	}

#ifndef POOR_WATER
	diff = 2.0f*radius - (GLASS_TOP - p_col.z);

	if (diff > EPSILON)
	{
		vec3_set(&n, 0.0f, 0.0f, -1.0f);;

		mat4_mulvec3_as_mat3(&n, mat, &n);
		compute_col(p, col, vel, &n, diff, stiff, damp);
	}
#endif
}

void cpu_sph_process_collision(cpu_sph* sph)
{
	int i;
	float e;
	float sphere_radius;
	float stiff;
	float damp;
//	const float EPSILON = 0.000001f;

//	stiff = 5000.0f;
	//stiff = 10000.0f;
	stiff = 30000.0f;
	damp = 128.0f;
	//damp = 64.0f;
	
	//sphere_radius = RADIUS;
	sphere_radius = 0.004f;
	e = 1.0f;


	for (i = 0; i < sph->n_particles; i++)
	{

		//float BOX_W = 0.08f; /** Width of box **/
		//float BOX_BOTTOM = -0.13f; /** Bottom of box **/
		float BOX_W = 0.065f; /** Width of box **/
		float BOX_BOTTOM = -0.08f; /** Bottom of box **/
//		_ALIGNED vector3 p; /** Position in collision coordinate **/
		//_ALIGNED vector3 vel; /** Velocity in collision coordinate **/

//        _ALIGNED vector3 n_w; /** Normal in world coordinate **/
		_ALIGNED vector3 pre_p; /** Predicted pos **/
		vector3 col;

#ifdef POOR_WATER
		vector3 n;
		float diff;
#endif

		vec3_set(&col, 0.0f, 0.0f, 0.0f);
		vec3_scaleadd(&pre_p, &POS(i), sph->timestep, &VELH(i));

#ifdef RIGID_BODY
		if (i < sph->n_rigidp[0])
			stiff = 50000.0f;
		else stiff = 30000.0f;
#endif

#ifdef GLASS
		cpu_sph_glass_collision(&pre_p, &col, &VEL(i),
			&sph->mat_col, &sph->mat_inv_col, sphere_radius, stiff, damp);
#endif
	

		/** Box **/
#ifdef POOR_WATER
		diff = 2.0f*sphere_radius - (pre_p.z - BOX_BOTTOM);
		if (diff > EPSILON)
		{
			vec3_set(&n, 0.0f, 0.0f, 1.0f);
			compute_col(&pre_p, &col, &VEL(i), &n, diff, stiff, damp);
		}

		diff = 2.0f*sphere_radius - (BOX_W - pre_p.x);
		if (diff > EPSILON)
		{
			vec3_set(&n, -1.0f, 0.0f, 0.0f);
			compute_col(&pre_p, &col, &VEL(i), &n, diff, stiff, damp);
		}

		diff = 2.0f*sphere_radius - (BOX_W + pre_p.x);
		if (diff > EPSILON)
		{
			vec3_set(&n, 1.0f, 0.0f, 0.0f);
			compute_col(&pre_p, &col, &VEL(i), &n, diff, stiff, damp);
		}

		diff = 2.0f*sphere_radius - (BOX_W - pre_p.y);
		if (diff > EPSILON)
		{
			vec3_set(&n, 0.0f, -1.0f, 0.0f);
			compute_col(&pre_p, &col, &VEL(i), &n, diff, stiff, damp);
		}

		diff = 2.0f*sphere_radius - (BOX_W + pre_p.y);
		if (diff > EPSILON)
		{
			vec3_set(&n, 0.0f, 1.0f, 0.0f);
			compute_col(&pre_p, &col, &VEL(i), &n, diff, stiff, damp);
		}
#endif

	
		vec3_add(&ACC(i), &ACC(i), &col);

	}

	return;
}


#ifdef RIGID_BODY
void cpu_sph_compute_rigid_body_motion(cpu_sph* sph, float t)
{
	int i;
	vector3 rg;
	vector3 T;
	vector3 R;
	vector3* q;
	vector3* temp_vel;
	vector3 g;
	float I;

	vec3_set(&g, 0.0f, 0.0f, -9.8f);

	q = (vector3*)malloc(sph->n_rigidp[0]*sizeof(vector3));
	temp_vel = (vector3*)malloc(sph->n_rigidp[0]*sizeof(vector3));

	// Compute new velocity
	FOR_EACH_RIGID(0, i)
	{
		_ALIGNED vector3 final_acc;

		vec3_add(&final_acc, &sph->acc[i], &g);
		vec3_scaleadd(&temp_vel[i], &VELH(i), t, &final_acc);
	}
	

	// Compute translational velocity
	vec3_set(&T, 0, 0, 0);
	FOR_EACH_RIGID(0, i)
		vec3_add(&T, &T, &temp_vel[i]);
	vec3_scale(&T, 1.0f/sph->n_rigidp[0], &T);
	//vec3_scaleadd(&T, &T, t, &g);

	// Update translational velocity
	//vec3_scaleadd(&sph->v_trans_half, &sph->v_trans_half, t, &T);

	// Compute center of gravity 
	vec3_set(&rg, 0.0f, 0.0f, 0.0f);
	FOR_EACH_RIGID(0, i)
		vec3_add(&rg, &rg, &POS(i));
	vec3_scale(&rg, 1.0f/sph->n_rigidp[0], &rg);

	// Compute angular velocity
	FOR_EACH_RIGID(0, i)
		vec3_sub(&q[i], &POS(i), &rg);

	I = 0;
	vec3_set(&R, 0.0f, 0.0f, 0.0f);
	FOR_EACH_RIGID(0, i)
	{
		vector3 c;
		I += vec3_lensq(&q[i]);

//		vec3_cross(&c, &temp_vel[i], &q[i]);
		vec3_cross(&c, &q[i], &temp_vel[i]);
		vec3_add(&R, &R, &c);
	}
	vec3_scale(&R, 1.0f/I, &R);

	
	// Compute rotation matrix
	{
		vector3 axis;
		matrix4 dr;
		float r = vec3_len(&R);
		vec3_scale(&axis, 1.0f/r, &R);
		mat4_set_rotate(&dr, t*r/M_PI*180.0f, axis.x, axis.y, axis.z);
		mat4_mul(&sph->r_rot, &dr, &sph->r_rot);
	}

	
	// Update velocity of each rigid body particles
	FOR_EACH_RIGID(0, i)
	{
		_ALIGNED vector3 v_half;

//		vec3_cross(&v_half, &q[i], &R);
		vec3_cross(&v_half, &R, &q[i]);
		vec3_add(&v_half, &v_half, &T);

		//vec3_scaleadd(&sph->pos[i], &sph->pos[i], t, &v_half);

		vec3_add(&VEL(i), &VELH(i), &v_half);
		vec3_scale(&VEL(i), 0.5f, &VEL(i));

		vec3_copy(&VELH(i), &v_half);
	}

	vec3_scaleadd(&rg, &rg, t, &T);

	
	FOR_EACH_RIGID(0, i)
	{
		_ALIGNED vector3 tempp;

		vec3_sub(&tempp, &sph->init_pos[i], &sph->rg0);
		mat4_mulvec3_as_mat3(&tempp, &sph->r_rot, &tempp);
		vec3_add(&POS(i), &tempp, &rg);
	}
	
	

	//vec3_scaleadd(&sph->r, &sph->r, t, &sph->w_half);
	vec3_copy(&sph->c, &rg);


	free(temp_vel);
	free(q);
}
#endif // RIGID_BODY



void cpu_sph_elapse(cpu_sph* sph, float t)
{
	int i;
	int j;
	_ALIGNED vector3 gravity;

	sph->timestep = t;

	vec3_set(&gravity, 0.0f, 0.0f, -9.8f);

	for (j = 0; j < sph->n_loops; j++)
	{
		if (j == 0)
		{
			sph_grid_clear(&sph->grid, sph->pos, 0, sph->n_particles - 1);
			sph_grid_alloc(&sph->grid, sph->pos, 0, sph->fluid_start - 1);
			sph_grid_get_neighbours(&sph->grid, sph->pos, sph->fluid_start, sph->n_particles - 1, &sph->n_list, sph->r_search);
		}


		cpu_sph_compute_density(sph, (j == 0));
		cpu_sph_compute_force(sph);
		cpu_sph_process_collision(sph);

#ifdef RIGID_BODY
		cpu_sph_compute_rigid_body_motion(sph, t);
#endif
		FOR_EACH_FLUID(i)
		{
			_ALIGNED vector3 v_half;
			_ALIGNED vector3 final_acc;

			vec3_add(&final_acc, &sph->acc[i], &gravity);

			vec3_scaleadd(&v_half, &VELH(i), t, &final_acc);
			vec3_scaleadd(&POS(i), &POS(i), t, &v_half);

			vec3_add(&VEL(i), &VELH(i), &v_half);
			vec3_scale(&VEL(i), 0.5f, &VEL(i));

			vec3_copy(&VELH(i), &v_half);
		}
	}
}

void cpu_sph_get_pos(cpu_sph* sph, vector3* pos)
{
	memcpy(pos, sph->pos, sph->n_particles*sizeof(vector3));
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?