Last active
August 7, 2019 22:09
-
-
Save litherum/1a68207326fe1675ef9843b7a83193c1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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