Skip to content

Instantly share code, notes, and snippets.

@litherum
Last active August 7, 2019 22:09
Show Gist options
  • Save litherum/1a68207326fe1675ef9843b7a83193c1 to your computer and use it in GitHub Desktop.
Save litherum/1a68207326fe1675ef9843b7a83193c1 to your computer and use it in GitHub Desktop.
MSL Vertex shader:
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 gl_Position [[position]];
};
struct main0_in
{
float2 a_particlePos [[attribute(0)]];
float2 a_particleVel [[attribute(1)]];
float2 a_pos [[attribute(2)]];
};
vertex main0_out main0(main0_in in [[stage_in]])
{
main0_out out = {};
float angle = -atan2(in.a_particleVel.x, in.a_particleVel.y);
float2 pos = float2((in.a_pos.x * cos(angle)) - (in.a_pos.y * sin(angle)), (in.a_pos.x * sin(angle)) + (in.a_pos.y * cos(angle)));
out.gl_Position = float4(pos + in.a_particlePos, 0.0, 1.0);
out.gl_Position.y = -(out.gl_Position.y); // Invert Y-axis for Metal
return out;
}
MSL Fragment shader:
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float4 fragColor [[color(0)]];
};
fragment main0_out main0()
{
main0_out out = {};
out.fragColor = float4(1.0);
return out;
}
MSL Compute shader:
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct Particle
{
float2 pos;
float2 vel;
};
struct ParticlesA
{
Particle particles[1500];
};
struct SimParams
{
float deltaT;
float rule1Distance;
float rule2Distance;
float rule3Distance;
float rule1Scale;
float rule2Scale;
float rule3Scale;
};
struct ParticlesB
{
Particle particles[1500];
};
kernel void main0(constant SimParams& params [[buffer(1)]], device ParticlesA& particlesA [[buffer(2)]], device ParticlesB& particlesB [[buffer(3)]], uint3 gl_GlobalInvocationID [[thread_position_in_grid]])
{
uint index = gl_GlobalInvocationID.x;
if (index >= 1500u)
{
return;
}
float2 vPos = particlesA.particles[index].pos;
float2 vVel = particlesA.particles[index].vel;
float2 cMass = float2(0.0);
float2 cVel = float2(0.0);
float2 colVel = float2(0.0);
int cMassCount = 0;
int cVelCount = 0;
for (int i = 0; i < 1500; i++)
{
if (uint(i) == index)
{
continue;
}
float2 pos = particlesA.particles[i].pos;
float2 vel = particlesA.particles[i].vel;
if (distance(pos, vPos) < params.rule1Distance)
{
cMass += pos;
cMassCount++;
}
if (distance(pos, vPos) < params.rule2Distance)
{
colVel -= (pos - vPos);
}
if (distance(pos, vPos) < params.rule3Distance)
{
cVel += vel;
cVelCount++;
}
}
if (cMassCount > 0)
{
cMass = (cMass / float2(float(cMassCount))) - vPos;
}
if (cVelCount > 0)
{
cVel /= float2(float(cVelCount));
}
vVel += (((cMass * params.rule1Scale) + (colVel * params.rule2Scale)) + (cVel * params.rule3Scale));
vVel = normalize(vVel) * fast::clamp(length(vVel), 0.0, 0.100000001490116119384765625);
vPos += (vVel * params.deltaT);
if (vPos.x < (-1.0))
{
vPos.x = 1.0;
}
if (vPos.x > 1.0)
{
vPos.x = -1.0;
}
if (vPos.y < (-1.0))
{
vPos.y = 1.0;
}
if (vPos.y > 1.0)
{
vPos.y = -1.0;
}
particlesB.particles[index].pos = vPos;
particlesB.particles[index].vel = vVel;
}
GLSL Vertex Shader:
#version 450
layout(location = 0) in vec2 a_particlePos;
layout(location = 1) in vec2 a_particleVel;
layout(location = 2) in vec2 a_pos;
void main() {
float angle = -atan(a_particleVel.x, a_particleVel.y);
vec2 pos = vec2(a_pos.x * cos(angle) - a_pos.y * sin(angle),
a_pos.x * sin(angle) + a_pos.y * cos(angle));
gl_Position = vec4(pos + a_particlePos, 0, 1);
}
GLSL Fragment Shader:
#version 450
layout(location = 0) out vec4 fragColor;
void main() {
fragColor = vec4(1.0);
}
GLSL Compute Shader:
#version 450
struct Particle {
vec2 pos;
vec2 vel;
};
layout(std140, set = 0, binding = 0) uniform SimParams {
float deltaT;
float rule1Distance;
float rule2Distance;
float rule3Distance;
float rule1Scale;
float rule2Scale;
float rule3Scale;
} params;
layout(std140, set = 0, binding = 1) buffer ParticlesA {
Particle particles[${numParticles}];
} particlesA;
layout(std140, set = 0, binding = 2) buffer ParticlesB {
Particle particles[${numParticles}];
} particlesB;
void main() {
// https://github.com/austinEng/Project6-Vulkan-Flocking/blob/master/data/shaders/computeparticles/particle.comp
uint index = gl_GlobalInvocationID.x;
if (index >= ${numParticles}) { return; }
vec2 vPos = particlesA.particles[index].pos;
vec2 vVel = particlesA.particles[index].vel;
vec2 cMass = vec2(0.0, 0.0);
vec2 cVel = vec2(0.0, 0.0);
vec2 colVel = vec2(0.0, 0.0);
int cMassCount = 0;
int cVelCount = 0;
vec2 pos;
vec2 vel;
for (int i = 0; i < ${numParticles}; ++i) {
if (i == index) { continue; }
pos = particlesA.particles[i].pos.xy;
vel = particlesA.particles[i].vel.xy;
if (distance(pos, vPos) < params.rule1Distance) {
cMass += pos;
cMassCount++;
}
if (distance(pos, vPos) < params.rule2Distance) {
colVel -= (pos - vPos);
}
if (distance(pos, vPos) < params.rule3Distance) {
cVel += vel;
cVelCount++;
}
}
if (cMassCount > 0) {
cMass = cMass / cMassCount - vPos;
}
if (cVelCount > 0) {
cVel = cVel / cVelCount;
}
vVel += cMass * params.rule1Scale + colVel * params.rule2Scale + cVel * params.rule3Scale;
// clamp velocity for a more pleasing simulation.
vVel = normalize(vVel) * clamp(length(vVel), 0.0, 0.1);
// kinematic update
vPos += vVel * params.deltaT;
// Wrap around boundary
if (vPos.x < -1.0) vPos.x = 1.0;
if (vPos.x > 1.0) vPos.x = -1.0;
if (vPos.y < -1.0) vPos.y = 1.0;
if (vPos.y > 1.0) vPos.y = -1.0;
particlesB.particles[index].pos = vPos;
// Write back
particlesB.particles[index].vel = vVel;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment