3 Minecraft Classic lava animation algorithm
Goodlyay edited this page 2021-06-06 21:37:16 -07:00

From goodlyay's dropbox

Thanks to John Alvarado for doing most of the work in figuring this out.

The algorithm uses a 3-layer cellular automata to simulate a dynamic heated fluid. The texture is a visualization of the heat of this fluid.

We will be using an analogy of a pot of boiling soup over fire. (All variable names have been made up for the purpose of this analogy.)

Each cellular automata layer is represented as a float array with 256 elements corresponding to the pixels of the texture.

The first layer represents the flameHeat (This can be negative.), The second layer represents the potHeat, The third layer represents the soupHeat.

All of these array values start at 0 when the game starts and are updated every tick.

Lava


Each frame, for every position in the lava texture array, it calculates the corresponding values of the soupHeat, potHeat, and flameHeat layers as follows:

Note: Any index that goes off the edge of the texture is wrapped around to the opposide side.

Calculates a localSoupHeat equal to the sum of the 3x3 soupHeat neighborhood around the current element but offset vertically by colSin******* and offset horizontally by rowSin*********.
	rowSin is 1.2 times the sign of an angle that starts at 0 and changes by 22.5 degrees every row.
	colSin is 1.2 times the sign of an angle that starts at 0 and changes by 22.5 degrees every column.

Calculates a localPotHeat equal to the sum of a 2x2 potHeat neighborhood around the current potHeat, with the current position being the upper left of the 2x2 neighborhood.


Calculates the new soupHeat as the sum of the localSoupHeat divided by 10 plus the localPotHeat divided by 4 times 0.8.

Calculates the new potHeat as the current potHeat plus the flameHeat times 0.01***************. potHeat is clamped to a minimum of 0.

Calculates the new flameHeat as the current flameHeat minus 0.06.
	However, there is a 0.005 in 1 random chance that flameHeat is set to 1.5.

After the above arrays are updated, for every pixel in the lava texture, it calculates the color based on the soupHeat as follows:

Calculates a colorHeat as double the soupHeat clamped between 0 and 1 inclusive.

Then it calculates the color components of the pixel as follows:
	float red = colorHeat * 100F + 155F
	float green = colorHeat^2 * 255F
	float blue = colorHeat^4 * 128F
	Alpha is opaque.
	
Finally, it converts the red green and blue to bytes and assigns them to the texture

Water


Each frame, for every position in the water texture array, it calculates the corresponding values of the soupHeat, potHeat, and flameHeat layers as follows:

Note: Any index that goes off the edge of the texture is wrapped around to the opposide side.

Calculates a localSoupHeat equal to the sum of the 3x1 soupHeat neighborhood around the current element. 

Calculates the new soupHeat as the sum of the localSoupHeat divided by 3.3F plus the potHeat times 0.8F

Calculates the new potHeat as the current potHeat plus the flameHeat times 0.05. potHeat is clamped to a minimum of 0.

Calculates the new flameHeat as the current flameHeat minus 0.1F.
	However, there is a 0.05 in 1 random chance that flameHeat is set to 0.5.

After the above arrays are updated, for every pixel in the water texture, it calculates the color based on the soupHeat as follows:

Calculates a colorHeat as the soupHeat clamped between 0 and 1 inclusive.

Then it calculates the color components of the pixel as follows:

	float red = 32 + colorHeat^2 * 32
	float green = 50 + colorHeat^2 * 64
	float blue = 255
	float alpha = 146 + colorHeat^2 * 50
	
Finally, it converts the red green and blue to bytes and assigns them to the texture