Add Margolus block CA sand physics shader
This commit is contained in:
parent
3787dbbc3a
commit
9e5af09476
2 changed files with 128 additions and 0 deletions
116
src/shaders/sandPhysics.frag
Normal file
116
src/shaders/sandPhysics.frag
Normal file
|
|
@ -0,0 +1,116 @@
|
||||||
|
precision highp float;
|
||||||
|
precision highp int;
|
||||||
|
|
||||||
|
in vec2 vUv;
|
||||||
|
|
||||||
|
uniform sampler2D uWorld;
|
||||||
|
uniform sampler2D uMaterialProps;
|
||||||
|
uniform vec2 uBlockOffset;
|
||||||
|
uniform int uFrame;
|
||||||
|
|
||||||
|
out vec4 fragColor;
|
||||||
|
|
||||||
|
uint hash(uint x) {
|
||||||
|
x ^= x >> 16u;
|
||||||
|
x *= 0x45d9f3bu;
|
||||||
|
x ^= x >> 16u;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
ivec2 pixel = ivec2(gl_FragCoord.xy);
|
||||||
|
ivec2 blockBase = ((pixel - ivec2(uBlockOffset)) / 2) * 2 + ivec2(uBlockOffset);
|
||||||
|
ivec2 localPos = pixel - blockBase;
|
||||||
|
int localIndex = localPos.x + localPos.y * 2;
|
||||||
|
|
||||||
|
// bounds check
|
||||||
|
int worldSize = int(WORLD_SIZE);
|
||||||
|
if (blockBase.x < 0 || blockBase.y < 0 ||
|
||||||
|
blockBase.x + 1 >= worldSize || blockBase.y + 1 >= worldSize) {
|
||||||
|
fragColor = texelFetch(uWorld, pixel, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read 2x2 block
|
||||||
|
vec4 cells[4];
|
||||||
|
float behaviors[4];
|
||||||
|
float densities[4];
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
ivec2 p = blockBase + ivec2(i % 2, i / 2);
|
||||||
|
cells[i] = texelFetch(uWorld, p, 0);
|
||||||
|
vec4 props = texelFetch(uMaterialProps, ivec2(int(cells[i].r), 0), 0);
|
||||||
|
behaviors[i] = props.r;
|
||||||
|
densities[i] = props.g;
|
||||||
|
}
|
||||||
|
|
||||||
|
// capture blocked state before vertical swaps modify the arrays
|
||||||
|
bool col0Blocked = (behaviors[0] == BEHAVIOR_SOLID || behaviors[2] == BEHAVIOR_SOLID || densities[0] <= densities[2]);
|
||||||
|
bool col1Blocked = (behaviors[1] == BEHAVIOR_SOLID || behaviors[3] == BEHAVIOR_SOLID || densities[1] <= densities[3]);
|
||||||
|
|
||||||
|
// random seed for this block this frame
|
||||||
|
uint seed = hash(uint(blockBase.x) * 7919u + uint(blockBase.y) * 6271u + uint(uFrame) * 3571u);
|
||||||
|
|
||||||
|
// try vertical gravity: column 0 (indices 0, 2) and column 1 (indices 1, 3)
|
||||||
|
// top=0,1 bottom=2,3
|
||||||
|
// block layout:
|
||||||
|
// [0][1] <- top row
|
||||||
|
// [2][3] <- bottom row
|
||||||
|
// if top is movable and top.density > bottom.density, swap
|
||||||
|
|
||||||
|
for (int col = 0; col < 2; col++) {
|
||||||
|
int top = col; // 0 or 1
|
||||||
|
int bot = col + 2; // 2 or 3
|
||||||
|
|
||||||
|
if (behaviors[top] != BEHAVIOR_SOLID && behaviors[bot] != BEHAVIOR_SOLID) {
|
||||||
|
if (densities[top] > densities[bot]) {
|
||||||
|
// swap entire vec4
|
||||||
|
vec4 tmp = cells[top];
|
||||||
|
cells[top] = cells[bot];
|
||||||
|
cells[bot] = tmp;
|
||||||
|
// update cached props
|
||||||
|
float tmpB = behaviors[top]; behaviors[top] = behaviors[bot]; behaviors[bot] = tmpB;
|
||||||
|
float tmpD = densities[top]; densities[top] = densities[bot]; densities[bot] = tmpD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try diagonal: if top cell still has high density and couldn't fall straight
|
||||||
|
// for top-left (0): can it go diagonal to bottom-right (3)?
|
||||||
|
// for top-right (1): can it go diagonal to bottom-left (2)?
|
||||||
|
// only if the cell directly below is blocked (same or higher density)
|
||||||
|
bool tryLeftFirst = (seed & 1u) == 0u;
|
||||||
|
|
||||||
|
if (tryLeftFirst) {
|
||||||
|
// try 0->3 diagonal (top-left to bottom-right)
|
||||||
|
if (col0Blocked && behaviors[0] != BEHAVIOR_SOLID && behaviors[3] != BEHAVIOR_SOLID &&
|
||||||
|
densities[0] > densities[3]) {
|
||||||
|
vec4 tmp = cells[0]; cells[0] = cells[3]; cells[3] = tmp;
|
||||||
|
float tmpB = behaviors[0]; behaviors[0] = behaviors[3]; behaviors[3] = tmpB;
|
||||||
|
float tmpD = densities[0]; densities[0] = densities[3]; densities[3] = tmpD;
|
||||||
|
}
|
||||||
|
// try 1->2 diagonal (top-right to bottom-left)
|
||||||
|
if (col1Blocked && behaviors[1] != BEHAVIOR_SOLID && behaviors[2] != BEHAVIOR_SOLID &&
|
||||||
|
densities[1] > densities[2]) {
|
||||||
|
vec4 tmp = cells[1]; cells[1] = cells[2]; cells[2] = tmp;
|
||||||
|
float tmpB = behaviors[1]; behaviors[1] = behaviors[2]; behaviors[2] = tmpB;
|
||||||
|
float tmpD = densities[1]; densities[1] = densities[2]; densities[2] = tmpD;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// try 1->2 first
|
||||||
|
if (col1Blocked && behaviors[1] != BEHAVIOR_SOLID && behaviors[2] != BEHAVIOR_SOLID &&
|
||||||
|
densities[1] > densities[2]) {
|
||||||
|
vec4 tmp = cells[1]; cells[1] = cells[2]; cells[2] = tmp;
|
||||||
|
float tmpB = behaviors[1]; behaviors[1] = behaviors[2]; behaviors[2] = tmpB;
|
||||||
|
float tmpD = densities[1]; densities[1] = densities[2]; densities[2] = tmpD;
|
||||||
|
}
|
||||||
|
// try 0->3
|
||||||
|
if (col0Blocked && behaviors[0] != BEHAVIOR_SOLID && behaviors[3] != BEHAVIOR_SOLID &&
|
||||||
|
densities[0] > densities[3]) {
|
||||||
|
vec4 tmp = cells[0]; cells[0] = cells[3]; cells[3] = tmp;
|
||||||
|
float tmpB = behaviors[0]; behaviors[0] = behaviors[3]; behaviors[3] = tmpB;
|
||||||
|
float tmpD = densities[0]; densities[0] = densities[3]; densities[3] = tmpD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragColor = cells[localIndex];
|
||||||
|
}
|
||||||
12
src/shaders/sandPhysics.vert
Normal file
12
src/shaders/sandPhysics.vert
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
precision highp float;
|
||||||
|
precision highp int;
|
||||||
|
|
||||||
|
in vec3 position;
|
||||||
|
in vec2 uv;
|
||||||
|
|
||||||
|
out vec2 vUv;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vUv = uv;
|
||||||
|
gl_Position = vec4(position, 1.0);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue