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.
190 lines
3.8 KiB
190 lines
3.8 KiB
#version 450
|
|
|
|
layout (local_size_x = 32) in;
|
|
|
|
struct Vertex {
|
|
vec3 position;
|
|
vec3 color;
|
|
vec2 uv;
|
|
vec3 normal;
|
|
vec3 velocity;
|
|
vec3 prevPosition;
|
|
float w;
|
|
};
|
|
|
|
struct Edge {
|
|
uint a;
|
|
uint b;
|
|
float restLength;
|
|
float compliance;
|
|
};
|
|
|
|
struct Tetrahedron {
|
|
uint a;
|
|
uint b;
|
|
uint c;
|
|
uint d;
|
|
float restVolume;
|
|
float compliance;
|
|
};
|
|
|
|
|
|
layout (std430, set = 0, binding = 0) buffer VertexBuffer {
|
|
Vertex vertices[];
|
|
};
|
|
|
|
layout (std430, set = 0, binding = 2) buffer EdgeBuffer {
|
|
Edge edges[];
|
|
};
|
|
|
|
layout (std430, set = 0, binding = 4) buffer TetrahedronBuffer {
|
|
Tetrahedron tetrahedra[];
|
|
};
|
|
|
|
layout (std140, set = 0, binding = 5) uniform Sizes {
|
|
uint vertexCount;
|
|
uint faceCount;
|
|
};
|
|
|
|
layout (std140, set = 1, binding = 0) uniform Properties {
|
|
vec3 gravity;
|
|
float dt;
|
|
uint k;
|
|
};
|
|
|
|
struct Partition {
|
|
uint offset;
|
|
uint size;
|
|
};
|
|
|
|
layout (push_constant, std430) uniform PushConstants {
|
|
uint state;
|
|
Partition edgePartition;
|
|
Partition tetrahedronPartition;
|
|
};
|
|
|
|
void preSolve(uint vID){
|
|
vertices[vID].prevPosition = vertices[vID].position;
|
|
if (vertices[vID].w == 0){
|
|
return;
|
|
}
|
|
vertices[vID].velocity += dt / k * gravity;
|
|
vertices[vID].position += dt / k * vertices[vID].velocity;
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
void solveEdge(uint eID){
|
|
Edge edge = edges[eID];
|
|
|
|
Vertex v1 = vertices[edge.a];
|
|
Vertex v2 = vertices[edge.b];
|
|
|
|
vec3 diff = v1.position - v2.position;
|
|
float currentLength = length(diff);
|
|
|
|
float alpha = edge.compliance / (dt / k) / (dt / k);
|
|
|
|
float s = -(currentLength - edge.restLength) / (v1.w + v2.w + alpha);
|
|
|
|
vec3 g1 = normalize(diff);
|
|
vec3 g2 = -g1;
|
|
|
|
vec3 delta1 = s * v1.w * g1;
|
|
vec3 delta2 = s * v2.w * g2;
|
|
|
|
vertices[edge.a].position += delta1;
|
|
vertices[edge.b].position += delta2;
|
|
}
|
|
|
|
void solveTetrahedron(uint tetID){
|
|
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;
|
|
|
|
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.w * dot(ga, ga) +
|
|
vb.w * dot(gb, gb) +
|
|
vc.w * dot(gc, gc) +
|
|
vd.w * dot(gd, gd);
|
|
|
|
if (w == 0) return;
|
|
|
|
float alpha = tetrahedron.compliance / (dt / k) / (dt / k);
|
|
|
|
float s = -volumeError / (w + alpha);
|
|
|
|
vec3 addA = s * ga * va.w;
|
|
vec3 addB = s * gb * vb.w;
|
|
vec3 addC = s * gc * vc.w;
|
|
vec3 addD = s * gd * vd.w;
|
|
|
|
vertices[tetrahedron.a].position += addA;
|
|
vertices[tetrahedron.b].position += addB;
|
|
vertices[tetrahedron.c].position += addC;
|
|
vertices[tetrahedron.d].position += addD;
|
|
}
|
|
|
|
void postSolve(uint vID){
|
|
if (vertices[vID].w == 0){
|
|
return;
|
|
}
|
|
vertices[vID].velocity = (vertices[vID].position - vertices[vID].prevPosition) / (dt / k);
|
|
}
|
|
|
|
void main() {
|
|
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);
|
|
} else if (id - edgePartition.size < tetrahedronPartition.size){
|
|
solveTetrahedron(id - edgePartition.size + tetrahedronPartition.offset);
|
|
}
|
|
break;
|
|
case 2:
|
|
if (id < vertexCount){
|
|
postSolve(id);
|
|
}
|
|
break;
|
|
}
|
|
} |