My Project
graphics/gravity_sim.cpp
/*******************************************************
* Copyright (c) 2014, ArrayFire
* All rights reserved.
*
* This file is distributed under 3-clause BSD license.
* The complete license agreement can be obtained at:
* http://arrayfire.com/licenses/BSD-3-Clause
********************************************************/
#include <arrayfire.h>
#include <iostream>
#include <cstdio>
using namespace af;
using namespace std;
static const int width = 512, height = 512;
static const int pixels_per_unit = 20;
void simulate(af::array *pos, af::array *vels, af::array *forces, float dt){
pos[0] += vels[0] * pixels_per_unit * dt;
pos[1] += vels[1] * pixels_per_unit * dt;
//calculate distance to center
af::array diff_x = pos[0] - width/2;
af::array diff_y = pos[1] - height/2;
af::array dist = sqrt( diff_x*diff_x + diff_y*diff_y );
//calculate normalised force vectors
forces[0] = -1 * diff_x / dist;
forces[1] = -1 * diff_y / dist;
//update force scaled to time and magnitude constant
forces[0] *= pixels_per_unit * dt;
forces[1] *= pixels_per_unit * dt;
//dampening
vels[0] *= 1 - (0.005*dt);
vels[1] *= 1 - (0.005*dt);
//update velocities from forces
vels[0] += forces[0];
vels[1] += forces[1];
}
void collisions(af::array *pos, af::array *vels){
//clamp particles inside screen border
af::array projected_px = min(width, max(0, pos[0]));
af::array projected_py = min(height - 1, max(0, pos[1]));
//calculate distance to center
af::array diff_x = projected_px - width/2;
af::array diff_y = projected_py - height/2;
af::array dist = sqrt( diff_x*diff_x + diff_y*diff_y );
//collide with center sphere
const int radius = 50;
const float elastic_constant = 0.91f;
if(sum<int>(dist<radius) > 0) {
vels[0](dist<radius) = -elastic_constant * vels[0](dist<radius);
vels[1](dist<radius) = -elastic_constant * vels[1](dist<radius);
//normalize diff vector
diff_x /= dist;
diff_y /= dist;
//place all particle colliding with sphere on surface
pos[0](dist<radius) = width/2 + diff_x(dist<radius) * radius;
pos[1](dist<radius) = height/2 + diff_y(dist<radius) * radius;
}
}
int main(int argc, char *argv[])
{
try {
const static int total_particles = 1000;
static const int reset = 500;
af::Window myWindow(width, height, "Gravity Simulation using ArrayFire");
int frame_count = 0;
// Initialize the kernel array just once
const af::array draw_kernel = gaussianKernel(3, 3);
af::array pos[2];
af::array vels[2];
af::array forces[2];
// Generate a random starting state
pos[0] = af::randu(total_particles) * width;
pos[1] = af::randu(total_particles) * height;
vels[0] = af::randn(total_particles);
vels[1] = af::randn(total_particles);
forces[0] = af::randn(total_particles);
forces[1] = af::randn(total_particles);
af::array image = af::constant(0, width, height);
af::array ids(total_particles, u32);
while(!myWindow.close()) {
float dt = af::timer::stop(timer);
ids = (pos[0].as(u32) * height) + pos[1].as(u32);
image(ids) += 255;
image = convolve2(image, draw_kernel);
myWindow.image(image);
image = af::constant(0, image.dims());
frame_count++;
// Generate a random starting state
if(frame_count % reset == 0) {
pos[0] = af::randu(total_particles) * width;
pos[1] = af::randu(total_particles) * height;
vels[0] = af::randn(total_particles);
vels[1] = af::randn(total_particles);
}
//check for collisions and adjust positions/velocities accordingly
collisions(pos, vels);
//run force simulation and update particles
simulate(pos, vels, forces, dt);
}
} catch (af::exception& e) {
fprintf(stderr, "%s\n", e.what());
throw;
}
return 0;
}
af::info
AFAPI void info()
af::constant
array constant(T val, const dim4 &dims, const dtype ty=(af_dtype) dtype_traits< T >::ctype)
af::timer::start
static AFAPI timer start()
af::array
A multi dimensional data container.
Definition: array.h:32
af
Definition: algorithm.h:13
af::gaussianKernel
AFAPI array gaussianKernel(const int rows, const int cols, const double sig_r=0, const double sig_c=0)
C++ Interface for generating gausian kernels.
af::max
AFAPI array max(const array &in, const int dim=-1)
C++ Interface for maximum values in an array.
af::randu
AFAPI array randu(const dim4 &dims, const dtype ty=f32)
af::array::dims
dim4 dims() const
Get dimensions of the array.
af::array::as
const array as(dtype type) const
Converts the array into another type.
af::sqrt
AFAPI array sqrt(const array &in)
C++ Interface for square root of input.
af::convolve2
AFAPI array convolve2(const array &signal, const array &filter, const convMode mode=AF_CONV_DEFAULT, const convDomain domain=AF_CONV_AUTO)
C++ Interface for convolution on two dimensional signals.
af::exception
Definition: exception.h:24
af::randn
AFAPI array randn(const dim4 &dims, const dtype ty=f32)
u32
32-bit unsigned integral values
Definition: defines.h:201
af::timer::stop
static AFAPI double stop()
arrayfire.h
af::timer
Internal timer object.
Definition: timing.h:34
af::exception::what
virtual const char * what() const
Definition: exception.h:45
af::Window
Window object to render af::arrays.
Definition: graphics.h:36
af::min
AFAPI array min(const array &in, const int dim=-1)
C++ Interface for minimum values in an array.