You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
3.7 KiB

4 months ago
#version 450
#extension GL_EXT_shader_atomic_float : enable
4 months ago
layout (local_size_x = 32) in;
#include "structs.comp"
4 months ago
4 months ago
layout (std430, set = 0, binding = 0) buffer VertexBuffer {
4 months ago
Vertex vertices[];
4 months ago
};
layout (std430, set = 0, binding = 2) buffer EdgeBuffer {
4 months ago
Edge edges[];
};
4 months ago
layout (std430, set = 0, binding = 4) buffer TetrahedronBuffer {
Tetrahedron tetrahedra[];
};
layout (std140, set = 0, binding = 5) uniform Sizes {
4 months ago
uint vertexCount;
uint faceCount;
};
layout (std140, set = 1, binding = 0) uniform Properties {
vec3 gravity;
float dt;
uint k;
};
4 months ago
struct Partition {
uint offset;
uint size;
4 months ago
};
4 months ago
layout (push_constant, std430) uniform PushConstants {
uint state;
Partition edgePartition;
Partition tetrahedronPartition;
4 months ago
};
void preSolve(uint vID){
4 months ago
vertices[vID].prevPosition = vertices[vID].position;
if (vertices[vID].inverseMass == 0){
4 months ago
return;
}
vertices[vID].velocity += dt / k * gravity;
vertices[vID].position += dt / k * vertices[vID].velocity;
4 months ago
float dist = vertices[vID].position.y + 5;
if (dist < 0){
vec3 normal = vec3(0, 1, 0);
vertices[vID].position -= dist * normal;
// contact friction
{
float mStatic = 1;
float mKinetic = 1;
vec3 a = vertices[vID].position - vertices[vID].prevPosition;
vec3 D = a - dot(a, normal) / dot(normal, normal) * normal;
vec3 add = -D;
if (length(D) >= mStatic * -dist){
add *= min(mKinetic * -dist / length(D), 1);
}
vertices[vID].position += add;
}
}
4 months ago
}
void solveEdge(uint eID){
4 months ago
Edge edge = edges[eID];
4 months ago
4 months ago
Vertex v1 = vertices[edge.a];
Vertex v2 = vertices[edge.b];
4 months ago
vec3 diff = v1.position - v2.position;
float currentLength = length(diff);
float alpha = edge.compliance / (dt / k) / (dt / k);
4 months ago
float s = -(currentLength - edge.restLength) / (v1.inverseMass + v2.inverseMass + alpha);
4 months ago
vec3 g1 = normalize(diff);
vec3 g2 = -g1;
vec3 delta1 = s * v1.inverseMass * g1;
vec3 delta2 = s * v2.inverseMass * g2;
4 months ago
4 months ago
vertices[edge.a].position += delta1;
vertices[edge.b].position += delta2;
4 months ago
}
void solveTetrahedron(uint tetID){
4 months ago
Tetrahedron tetrahedron = tetrahedra[tetID];
Vertex va = vertices[tetrahedron.a];
Vertex vb = vertices[tetrahedron.b];
Vertex vc = vertices[tetrahedron.c];
Vertex vd = vertices[tetrahedron.d];
vec3 a = va.position;
vec3 b = vb.position;
vec3 c = vc.position;
vec3 d = vd.position;
float volumeError = dot(d - a, cross(b - a, c - a)) / 6 - tetrahedron.restVolume;
4 months ago
vec3 ga = cross(d - b, c - b) / 6;
vec3 gb = cross(c - a, d - a) / 6;
vec3 gc = cross(d - a, b - a) / 6;
vec3 gd = cross(b - a, c - a) / 6;
float w =
va.inverseMass * dot(ga, ga) +
vb.inverseMass * dot(gb, gb) +
vc.inverseMass * dot(gc, gc) +
vd.inverseMass * dot(gd, gd);
4 months ago
4 months ago
if (w == 0) return;
4 months ago
float alpha = tetrahedron.compliance / (dt / k) / (dt / k);
4 months ago
4 months ago
float s = -volumeError / (w + alpha);
4 months ago
vec3 addA = s * ga * va.inverseMass;
vec3 addB = s * gb * vb.inverseMass;
vec3 addC = s * gc * vc.inverseMass;
vec3 addD = s * gd * vd.inverseMass;
4 months ago
4 months ago
vertices[tetrahedron.a].position += addA;
vertices[tetrahedron.b].position += addB;
vertices[tetrahedron.c].position += addC;
vertices[tetrahedron.d].position += addD;
}
4 months ago
void postSolve(uint vID){
if (vertices[vID].inverseMass == 0){
4 months ago
return;
}
vertices[vID].velocity = (vertices[vID].position - vertices[vID].prevPosition) / (dt / k);
}
void main() {
4 months ago
uint id = gl_GlobalInvocationID.x;
switch (state){
case 0:
if (id < vertexCount){
preSolve(id);
}
break;
case 1:
if (id < edgePartition.size){
solveEdge(id + edgePartition.offset);
4 months ago
} else if (id - edgePartition.size < tetrahedronPartition.size){
solveTetrahedron(id - edgePartition.size + tetrahedronPartition.offset);
4 months ago
}
break;
case 2:
if (id < vertexCount){
postSolve(id);
}
break;
}
4 months ago
}