Skip to content

Commit

Permalink
Added Example 40: Cloth simulation using compute shader
Browse files Browse the repository at this point in the history
  • Loading branch information
McNopper committed Jul 17, 2014
1 parent f80c52e commit 63facf1
Show file tree
Hide file tree
Showing 10 changed files with 681 additions and 75 deletions.
1 change: 1 addition & 0 deletions Example40/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/x86__Windows__MinGW_Debug/
228 changes: 215 additions & 13 deletions Example40/shader/cloth.comp.glsl
Original file line number Diff line number Diff line change
@@ -1,30 +1,232 @@
#version 430 core

layout(std430, binding=1) buffer VertexIn {
vec4 b_vertexIn[];
// Number of iterations the spring constraints and collisions are updated.
#define ITERATIONS 4

// Unit: kg * m * s*s
#define FORCE vec4(0.0, -0.2, 0.0, 0.0)

// Unit: kg
#define MASS 0.5

// Offset, that a particle is not inside the sphere surface.
#define RADIUS_TOLERANCE 0.01

uniform int u_verticesPerRow;

uniform float u_deltaTime;

// Distance at rest between vertical and horizontal particle.
uniform float u_distanceRest;

// One coliding sphere.
uniform vec4 u_sphereCenter;
uniform float u_sphereRadius;

layout(std430, binding=1) buffer VertexInPrevious {
vec4 b_vertexInPrevious[];
};

layout(std430, binding=2) buffer VertexInCurrent {
vec4 b_vertexInCurrent[];
};

layout(std430, binding=2) buffer VertexOut {
layout(std430, binding=3) buffer VertexOut {
vec4 b_vertexOut[];
};

layout(std430, binding=3) buffer NormalOut {
layout(std430, binding=4) buffer NormalOut {
vec3 b_normalOut[];
// Padding[]
};

// If ROWS and COLUMS change in the main file, update local size as well.
// (ROWS+1)*(COLUMNS+1)
layout (local_size_x = 121) in;
// (ROWS+1)^2
layout (local_size_x = 1024) in;

void calculateDeltaVector(out vec4 deltaVector, vec4 a, vec4 b)
{
vec4 vector = a - b;

float deltaLength = length(vector);

// 0.5 because this happens on each side.
deltaVector = vector * 0.5 * (u_distanceRest - deltaLength) / deltaLength;
}

// see http://web.archive.org/web/20070610223835/http://www.teknikus.dk/tj/gdc2001.htm
// http://developer.download.nvidia.com/SDK/10/direct3d/Source/Cloth/doc/Cloth.pdf
void main(void)
{
uint i = gl_GlobalInvocationID.x;
int currentIndex = int(gl_GlobalInvocationID.x) + int(gl_GlobalInvocationID.y) * u_verticesPerRow;

int currentIndexRow = currentIndex % u_verticesPerRow;
int currentIndexColumn = currentIndex / u_verticesPerRow;

//
// Summing all forces, to get the acceleration. In this case, only one force directing downwards is used to simulate gravity.
//

vec4 a = FORCE / MASS;

//
// Verlet integration.
//

float squareDeltaTime = u_deltaTime * u_deltaTime;

vec4 x = b_vertexInCurrent[currentIndex];

vec4 xPrev = b_vertexInPrevious[currentIndex];

// TODO Do cloth simulation, as seen:
// http://web.archive.org/web/20070610223835/http://www.teknikus.dk/tj/gdc2001.htm
// http://developer.download.nvidia.com/SDK/10/direct3d/Source/Cloth/doc/Cloth.pdf
b_vertexOut[currentIndex] = 2.0 * x - xPrev + a * squareDeltaTime;

memoryBarrierBuffer();

//
// Relaxation iterations.
//
for (int iteration = 0; iteration < ITERATIONS; iteration++)
{
//
// Process spring constraints.
//

// Alternating "even" and "odd" cells to avoid dependencies.
for (int evenOdd = 0; evenOdd < 2; evenOdd++)
{
int rightIndex;
int bellowIndex;
int diagonalIndex;

vec4 deltaVector;

if (currentIndexRow % 2 == evenOdd && currentIndexColumn % 2 == evenOdd)
{
rightIndex = currentIndex + 1;
if (rightIndex % u_verticesPerRow > currentIndexRow)
{
calculateDeltaVector(deltaVector, b_vertexOut[currentIndex], b_vertexOut[rightIndex]);

b_vertexOut[currentIndex] += deltaVector;
b_vertexOut[rightIndex] -= deltaVector;

memoryBarrierBuffer();
}


bellowIndex = currentIndex + u_verticesPerRow;
if (bellowIndex < u_verticesPerRow * u_verticesPerRow)
{
calculateDeltaVector(deltaVector, b_vertexOut[currentIndex], b_vertexOut[bellowIndex]);

b_vertexOut[currentIndex] += deltaVector;
b_vertexOut[bellowIndex] -= deltaVector;

memoryBarrierBuffer();
}


diagonalIndex = currentIndex + 1 + u_verticesPerRow;
if (diagonalIndex < u_verticesPerRow * u_verticesPerRow && diagonalIndex % u_verticesPerRow > currentIndexRow)
{
calculateDeltaVector(deltaVector, b_vertexOut[rightIndex], b_vertexOut[diagonalIndex]);

b_vertexOut[rightIndex] += deltaVector;
b_vertexOut[diagonalIndex] -= deltaVector;

memoryBarrierBuffer();

calculateDeltaVector(deltaVector, b_vertexOut[bellowIndex], b_vertexOut[diagonalIndex]);

b_vertexOut[bellowIndex] += deltaVector;
b_vertexOut[diagonalIndex] -= deltaVector;

memoryBarrierBuffer();
}
}
else if (evenOdd == 1 && currentIndexRow % 2 == 1 && currentIndexColumn == 0)
{
// First row spring, when processing odd pass.

rightIndex = currentIndex + 1;
if (rightIndex < u_verticesPerRow)
{
calculateDeltaVector(deltaVector, b_vertexOut[currentIndex], b_vertexOut[rightIndex]);

b_vertexOut[currentIndex] += deltaVector;
b_vertexOut[rightIndex] -= deltaVector;

memoryBarrierBuffer();
}
}

barrier();
}

//
// Process collision constraints.
//

vec4 sphereVector = b_vertexOut[currentIndex] - u_sphereCenter;

// If particle is inside sphere ...
if (length(sphereVector) < u_sphereRadius + RADIUS_TOLERANCE)
{
// ... move it outside the sphere.
b_vertexOut[currentIndex] = u_sphereCenter + normalize(sphereVector) * (u_sphereRadius + RADIUS_TOLERANCE);

memoryBarrierBuffer();
}

barrier();
}

//
// Calculate normal.
//

vec3 normal = vec3(0.0, 0.0, 0.0);

vec3 tangent;
vec3 bitangent;

b_vertexOut[i] = b_vertexIn[i];
b_normalOut[i] = vec3(0.0, 1.0, 0.0);
// Taking all neighbour particles, if available, into account.
if (currentIndexRow + 1 < u_verticesPerRow)
{
tangent = normalize((b_vertexOut[currentIndex + 1] - b_vertexOut[currentIndex]).xyz);

if (currentIndexColumn + 1 < u_verticesPerRow)
{
bitangent = normalize((b_vertexOut[currentIndex + u_verticesPerRow] - b_vertexOut[currentIndex]).xyz);

normal += normalize(cross(bitangent, tangent));
}
if (currentIndexColumn - 1 >= 0)
{
bitangent = normalize((b_vertexOut[currentIndex] - b_vertexOut[currentIndex - u_verticesPerRow]).xyz);

normal += normalize(cross(bitangent, tangent));
}
}
if (currentIndexRow - 1 >= 0)
{
tangent = normalize((b_vertexOut[currentIndex] - b_vertexOut[currentIndex - 1]).xyz);

if (currentIndexColumn + 1 < u_verticesPerRow)
{
bitangent = normalize((b_vertexOut[currentIndex + u_verticesPerRow] - b_vertexOut[currentIndex]).xyz);

normal += normalize(cross(bitangent, tangent));
}
if (currentIndexColumn - 1 >= 0)
{
bitangent = normalize((b_vertexOut[currentIndex] - b_vertexOut[currentIndex - u_verticesPerRow]).xyz);

normal += normalize(cross(bitangent, tangent));
}
}

//

b_normalOut[currentIndex] = normalize(normal);
}
8 changes: 6 additions & 2 deletions Example40/shader/cloth.frag.glsl
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
#version 430 core

in vec4 v_color;
uniform vec3 u_lightDirection;
uniform vec4 u_color;

in vec3 v_normal;

out vec4 fragColor;

void main(void)
{
fragColor = v_color;
// Two sided rendering, so use absolute value.
fragColor = u_color * abs(dot(normalize(v_normal), u_lightDirection));
}
22 changes: 6 additions & 16 deletions Example40/shader/cloth.vert.glsl
Original file line number Diff line number Diff line change
@@ -1,26 +1,16 @@
#version 430 core

layout(std430, binding=1) buffer Vertex {
vec4 b_vertex[];
};

layout(std430, binding=2) buffer Normal {
vec3 b_normal[];
// Padding[]
};

uniform mat4 u_modelViewProjectionMatrix;
uniform mat3 u_normalMatrix;
uniform vec3 u_lightDirection;
uniform vec4 u_color;

out vec4 v_color;
in vec4 a_vertex;
in vec4 a_normal;

out vec3 v_normal;

void main(void)
{
vec3 normal = u_normalMatrix * b_normal[gl_VertexID];

v_color = u_color * max(dot(normal, u_lightDirection), 0.0);
v_normal = u_normalMatrix * a_normal.xyz;

gl_Position = u_modelViewProjectionMatrix * b_vertex[gl_VertexID];
gl_Position = u_modelViewProjectionMatrix * a_vertex;
}
13 changes: 13 additions & 0 deletions Example40/shader/sphere.frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#version 430 core

uniform vec3 u_lightDirection;
uniform vec4 u_color;

in vec3 v_normal;

out vec4 fragColor;

void main(void)
{
fragColor = u_color * max(dot(normalize(v_normal), u_lightDirection), 0.0);
}
16 changes: 16 additions & 0 deletions Example40/shader/sphere.vert.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#version 430 core

uniform mat4 u_modelViewProjectionMatrix;
uniform mat3 u_normalMatrix;

in vec4 a_vertex;
in vec3 a_normal;

out vec3 v_normal;

void main(void)
{
v_normal = u_normalMatrix * a_normal;

gl_Position = u_modelViewProjectionMatrix * a_vertex;
}
Loading

0 comments on commit 63facf1

Please sign in to comment.