[Bf-blender-cvs] [5c8804d] fracture_modifier: fixes to prevent unwanted smoke "explosions" in the domain when using moving colliders, thanks to angavrilov for investigating those problems and providing this fixes.

Martin Felke noreply at git.blender.org
Sun Jul 17 21:32:41 CEST 2016


Commit: 5c8804d6aea27eceff71554e3fedeb6f97035bf5
Author: Martin Felke
Date:   Sun Jul 17 21:31:44 2016 +0200
Branches: fracture_modifier
https://developer.blender.org/rB5c8804d6aea27eceff71554e3fedeb6f97035bf5

fixes to prevent unwanted smoke "explosions" in the domain when using moving colliders, thanks to angavrilov for investigating those problems and providing this fixes.

===================================================================

M	intern/smoke/intern/FLUID_3D.cpp
M	intern/smoke/intern/FLUID_3D.h
M	source/blender/blenkernel/intern/smoke.c

===================================================================

diff --git a/intern/smoke/intern/FLUID_3D.cpp b/intern/smoke/intern/FLUID_3D.cpp
index 4faec89..f80a96f 100644
--- a/intern/smoke/intern/FLUID_3D.cpp
+++ b/intern/smoke/intern/FLUID_3D.cpp
@@ -993,6 +993,9 @@ void FLUID_3D::project()
 
 	copyBorderAll(_pressure, 0, _zRes);
 
+	// fix fluid compression caused in isolated components by obstacle movement
+	fixObstacleCompression(_divergence);
+
 	// solve Poisson equation
 	solvePressurePre(_pressure, _divergence, _obstacles);
 
@@ -1291,6 +1294,125 @@ void FLUID_3D::setObstacleBoundaries(float *_pressure, int zBegin, int zEnd)
 	}	// z-loop
 }
 
+void FLUID_3D::replaceComponentRec(int *buffer, size_t limit, size_t pos, int from, int to)
+{
+	/* Recursively replace 'from' with 'to' in the grid. Rely on (from != 0 && edges == 0) to stop. */
+	int offsets[] = { -1, +1, -_xRes, +_xRes, -_slabSize, +_slabSize };
+
+	buffer[pos] = to;
+
+	for (int i = 0; i < 6; i++) {
+		size_t next = pos + offsets[i];
+
+		if (next < limit && buffer[next] == from)
+			replaceComponentRec(buffer, limit, next, from, to);
+	}
+}
+
+void FLUID_3D::mergeComponents(int *buffer, size_t cur, size_t other)
+{
+	/* Replace higher value with lower. */
+	if (buffer[other] < buffer[cur]) {
+		replaceComponentRec(buffer, cur, cur, buffer[cur], buffer[other]);
+	}
+	else if (buffer[cur] < buffer[other]) {
+		replaceComponentRec(buffer, cur, other, buffer[other], buffer[cur]);
+	}
+}
+
+void FLUID_3D::fixObstacleCompression(float *divergence)
+{
+	int x, y, z;
+	size_t index;
+
+	/* Find compartments completely separated by obstacles.
+	 * Edge of the domain is automatically component 0. */
+	int *component = new int[_totalCells];
+	memset(component, 0, sizeof(int) * _totalCells);
+
+	int next_id = 1;
+
+	for (z = 1, index = _slabSize + _xRes + 1; z < _zRes - 1; z++, index += 2 * _xRes)
+	{
+		for (y = 1; y < _yRes - 1; y++, index += 2)
+		{
+			for (x = 1; x < _xRes - 1; x++, index++)
+			{
+				if(!_obstacles[index])
+				{
+					/* Check for connection to the domain edge at iteration end. */
+					if ((x == _xRes-2 && !_obstacles[index + 1]) ||
+					    (y == _yRes-2 && !_obstacles[index + _xRes]) ||
+					    (z == _zRes-2 && !_obstacles[index + _slabSize]))
+					{
+						component[index] = 0;
+					}
+					else {
+						component[index] = next_id;
+					}
+
+					if (!_obstacles[index - 1])
+						mergeComponents(component, index, index - 1);
+					if (!_obstacles[index - _xRes])
+						mergeComponents(component, index, index - _xRes);
+					if (!_obstacles[index - _slabSize])
+						mergeComponents(component, index, index - _slabSize);
+
+					if (component[index] == next_id)
+						next_id++;
+				}
+			}
+		}
+	}
+
+	/* Compute average divergence within each component. */
+	float *total_divergence = new float[next_id];
+	int *component_size = new int[next_id];
+
+	memset(total_divergence, 0, sizeof(float) * next_id);
+	memset(component_size, 0, sizeof(int) * next_id);
+
+	for (z = 1, index = _slabSize + _xRes + 1; z < _zRes - 1; z++, index += 2 * _xRes)
+	{
+		for (y = 1; y < _yRes - 1; y++, index += 2)
+		{
+			for (x = 1; x < _xRes - 1; x++, index++)
+			{
+				if(!_obstacles[index])
+				{
+					int ci = component[index];
+
+					component_size[ci]++;
+					total_divergence[ci] += divergence[index];
+				}
+			}
+		}
+	}
+
+	/* Adjust divergence to make the average zero in each component except the edge. */
+	total_divergence[0] = 0.0f;
+
+	for (z = 1, index = _slabSize + _xRes + 1; z < _zRes - 1; z++, index += 2 * _xRes)
+	{
+		for (y = 1; y < _yRes - 1; y++, index += 2)
+		{
+			for (x = 1; x < _xRes - 1; x++, index++)
+			{
+				if(!_obstacles[index])
+				{
+					int ci = component[index];
+
+					divergence[index] -= total_divergence[ci] / component_size[ci];
+				}
+			}
+		}
+	}
+
+	delete[] component;
+	delete[] component_size;
+	delete[] total_divergence;
+}
+
 //////////////////////////////////////////////////////////////////////
 // add buoyancy forces
 //////////////////////////////////////////////////////////////////////
@@ -1650,4 +1772,4 @@ void FLUID_3D::updateFlame(float *react, float *flame, int total_cells)
 		else
 			flame[index] = 0.0f;
 	}
-}
\ No newline at end of file
+}
diff --git a/intern/smoke/intern/FLUID_3D.h b/intern/smoke/intern/FLUID_3D.h
index cd2147b..5335183 100644
--- a/intern/smoke/intern/FLUID_3D.h
+++ b/intern/smoke/intern/FLUID_3D.h
@@ -195,6 +195,8 @@ struct FLUID_3D
 		void setObstacleBoundaries(float *_pressure, int zBegin, int zEnd);
 		void setObstaclePressure(float *_pressure, int zBegin, int zEnd);
 
+		void fixObstacleCompression(float *divergence);
+
 	public:
 		// advection, accessed e.g. by WTURBULENCE class
 		//void advectMacCormack();
@@ -202,6 +204,9 @@ struct FLUID_3D
 		void advectMacCormackEnd1(int zBegin, int zEnd);
 		void advectMacCormackEnd2(int zBegin, int zEnd);
 
+		void replaceComponentRec(int *components, size_t limit, size_t pos, int from, int to);
+		void mergeComponents(int *components, size_t cur, size_t other);
+
 		/* burning */
 		float *_burning_rate; // RNA pointer
 		float *_flame_smoke; // RNA pointer
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index d20994a..200f874 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -707,6 +707,7 @@ typedef struct ObstaclesFromDMData {
 	bool has_velocity;
 	float *vert_vel;
 	float *velocityX, *velocityY, *velocityZ;
+	int *num_obstacles;
 } ObstaclesFromDMData;
 
 static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
@@ -755,8 +756,10 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
 				/* tag obstacle cells */
 				data->obstacle_map[index] = 1;
 
-				if (data->has_velocity)
+				if (data->has_velocity) {
 					data->obstacle_map[index] |= 8;
+					data->num_obstacles[index]++;
+				}
 			}
 		}
 	}
@@ -764,7 +767,7 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z)
 
 static void obstacles_from_derivedmesh(
         Object *coll_ob, SmokeDomainSettings *sds, SmokeCollSettings *scs,
-        unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, float dt)
+        unsigned char *obstacle_map, float *velocityX, float *velocityY, float *velocityZ, int *num_obstacles, float dt)
 {
 	if (!scs->dm) return;
 	{
@@ -835,7 +838,8 @@ static void obstacles_from_derivedmesh(
 			    .sds = sds, .mvert = mvert, .mloop = mloop, .looptri = looptri,
 			    .tree = &treeData, .obstacle_map = obstacle_map,
 			    .has_velocity = has_velocity, .vert_vel = vert_vel,
-			    .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ
+			    .velocityX = velocityX, .velocityY = velocityY, .velocityZ = velocityZ,
+			    .num_obstacles = num_obstacles
 			};
 			BLI_task_parallel_range(
 			            sds->res_min[2], sds->res_max[2], &data, obstacles_from_derivedmesh_task_cb, true);
@@ -871,6 +875,8 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
 	float *b = smoke_get_color_b(sds->fluid);
 	unsigned int z;
 
+	int *num_obstacles = MEM_callocN(sizeof(int) * sds->res[0] * sds->res[1] * sds->res[2], "smoke_num_obstacles");
+
 	smoke_get_ob_velocity(sds->fluid, &velx, &vely, &velz);
 
 	// TODO: delete old obstacle flags
@@ -900,7 +906,7 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
 		if ((smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll)
 		{
 			SmokeCollSettings *scs = smd2->coll;
-			obstacles_from_derivedmesh(collob, sds, scs, obstacles, velx, vely, velz, dt);
+			obstacles_from_derivedmesh(collob, sds, scs, obstacles, velx, vely, velz, num_obstacles, dt);
 		}
 	}
 
@@ -926,7 +932,15 @@ static void update_obstacles(Scene *scene, Object *ob, SmokeDomainSettings *sds,
 				b[z] = 0;
 			}
 		}
+		/* average velocities from multiple obstacles in one cell */
+		if (num_obstacles[z]) {
+			velx[z] /= num_obstacles[z];
+			vely[z] /= num_obstacles[z];
+			velz[z] /= num_obstacles[z];
+		}
 	}
+
+	MEM_freeN(num_obstacles);
 }
 
 /**********************************************************




More information about the Bf-blender-cvs mailing list