diff --git a/Ball.cpp b/Ball.cpp index 809e812..7f6c0f0 100644 --- a/Ball.cpp +++ b/Ball.cpp @@ -2,25 +2,27 @@ #include #include -Ball::Ball(const Point& _center, double _min_height, double _v_x, +Ball::Ball(const Point& _center, double _min_height, double _v_x, double _v_z, double _p, double _q) : Center(_center), - surface(_center, _p, _q), - init_h(_center.z), + surface(_center, min_height, _p, _q), + init_h(_center.y), min_height(_min_height), bounce_number(0.0), crt_time(0), - A(_center.z), + A(_center.y), B(0), - U(sqrt(2 * G_CTE * _center.z)), - T(sqrt(2.0 * _center.z / G_CTE)), - v_x(_v_x) + U(sqrt(2 * G_CTE * _center.y)), + T(sqrt(2.0 * _center.y / G_CTE)), + v_x(_v_x), + v_z(_v_z) { } void Ball::_compute_pos(double dt) { - Center.z = fmax(0.0, A + B * crt_time - (G_CTE / 2) * crt_time * crt_time + min_height); + Center.y = fmax(0.0, A + B * crt_time - (G_CTE / 2) * crt_time * crt_time + min_height); Center.x += dt * v_x; + Center.z += dt * v_z; surface.update_center_pos(Center); } @@ -40,19 +42,27 @@ void Ball::_compute_U_n() { U *= 0.5; } -void Ball::_compute_v_x() { - v_x *= 0.5; +void Ball::_compute_v_x(Point normal) { + double factor = normal.x / (4*(normal.x + normal.z)); + v_x *= (0.5 + factor); +} + +void Ball::_compute_v_z(Point normal) { + double factor = normal.x / (4*(normal.x + normal.z)); + v_z *= (0.5 + factor); } void Ball::update_pos(double dt) { crt_time += dt; if (crt_time >= T) { + Point normal = surface.getNormalVector(); bounce_number += 1; _compute_U_n(); _compute_A_n(); _compute_B_n(); _compute_T_n(); - _compute_v_x(); + _compute_v_x(normal); + _compute_v_z(normal); std::cout << "New bounce :"; std::cout << "U:" << U << ":"; std::cout << "A:" << A << ":"; @@ -67,7 +77,7 @@ std::ostream& operator<< (std::ostream &out, Ball const& data) { out << "t:" << data.access_crt_time() << ":"; out << "T:" << data.accessT() << ":"; out << center.x << ':'; - out << center.y << ':'; out << center.z << ':'; + out << center.y << ':'; return out; } diff --git a/Ball.hpp b/Ball.hpp index b065e3d..60ed9bc 100644 --- a/Ball.hpp +++ b/Ball.hpp @@ -24,16 +24,17 @@ class Ball { size_t bounce_number; double crt_time; double A, B, U, T; // Coefficients for the physical model. - double v_x; + double v_x, v_z; void _compute_pos(double dt); - void _compute_v_x(); + void _compute_v_x(Point normal); + void _compute_v_z(Point normal); void _compute_A_n(); void _compute_B_n(); void _compute_U_n(); void _compute_T_n(); public: Ball(const Point& _center, double _min_height, double _v_x, - double p, double q); + double _v_z, double p, double q); void update_pos(double dt); Point getCenter() const {return Center;} double accessT() const { return T;} diff --git a/Makefile b/Makefile index b5d37ec..7a7570b 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ OBJS=Implicit.o \ Mesh.o \ spheroid.o \ Ball.o \ + PerlinNoise.o \ util/ObjParser.o \ MarchingCubes.o \ _gen/marching_cubes_data.o \ diff --git a/PerlinNoise.cpp b/PerlinNoise.cpp new file mode 100644 index 0000000..af46b57 --- /dev/null +++ b/PerlinNoise.cpp @@ -0,0 +1,123 @@ +#include "PerlinNoise.hpp" + +Point vector_product(Point u, Point v) { + Point u_v(0,0,0); + u_v.x = u.y* v.z - u.z * v.y; + u_v.y = u.z* v.x - u.x * v.z; + u_v.z = u.x* v.y - u.y * v.x; + return u_v; +} + +PerlinNoise::PerlinNoise() : ImplicitSurface(Point(0,0,0)) { + // permutation vector (source : http://mrl.nyu.edu/~perlin/noise/) + p = { + 151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142, + 8,99,37,240,21,10,23,190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117, + 35,11,32,57,177,33,88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71, + 134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41, + 55,46,245,40,244,102,143,54, 65,25,63,161,1,216,80,73,209,76,132,187,208, 89, + 18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226, + 250,124,123,5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182, + 189,28,42,223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, + 43,172,9,129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246, + 97,228,251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239, + 107,49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, + 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 }; + // Duplication of the permutation vector. + p.insert(p.end(), p.begin(), p.end()); +} + +PerlinNoise::PerlinNoise(unsigned int seed) : ImplicitSurface(Point(0,0,0)) { + p.resize(256); + + // Fill p with values from 0 to 255 + std::iota(p.begin(), p.end(), 0); + + // Initialize a random engine with seed + std::default_random_engine engine(seed); + + // Shuffle using the above random engine + std::shuffle(p.begin(), p.end(), engine); + + // Duplicate the permutation vector + p.insert(p.end(), p.begin(), p.end()); +} + +double PerlinNoise::operator() (double x, double y, double z) const { + return z - noise(x, y, 0); +} + +double PerlinNoise::noise(double _x, double _y, double _z) const { + int X = (int) floor(_x) & 255; + int Y = (int) floor(_y) & 255; + int Z = (int) floor(_z) & 255; + + _x -= floor(_x); + _y -= floor(_y); + _z -= floor(_z); + + double u = fade(_x); + double v = fade(_y); + double w = fade(_z); + + int A = p[X] + Y; + int AA = p[A] + Z; + int AB = p[A + 1] + Z; + int B = p[X + 1] + Y; + int BA = p[B] + Z; + int BB = p[B + 1] + Z; + + double res = lerp( + w, + lerp( + v, + lerp(u, grad(p[AA], _x, _y, _z), grad(p[BA], _x-1, _y, _z)), + lerp(u, grad(p[AB], _x, _y-1, _z), grad(p[BB], _x-1, _y-1, _z)) + ), + lerp( + v, + lerp( + u, + grad(p[AA+1], _x, _y, _z-1), + grad(p[BA+1], _x-1, _y, _z-1) + ), + lerp( + u, + grad(p[AB+1], _x, _y-1, _z-1), + grad(p[BB+1], _x-1, _y-1, _z-1) + ) + ) + ); + return (res + 1.0)/2.0; +} + +double PerlinNoise::noise(double _x, double _y) const { + return noise(_x, _y, 0); +} + +double PerlinNoise::fade(double t) const { + return t * t * t * (t * (t * 6 - 15) + 10); +} + +double PerlinNoise::lerp(double t, double a, double b) const { + return a + t * (b-a); +} + +double PerlinNoise::grad(int hash, double x, double y, double z) const { + int h = hash & 15; + // Convert lower 4 bits of hash into 12 gradient directions + double u = h < 8 ? x : y, + v = h < 4 ? y : h == 12 || h == 14 ? x : z; + return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); +} + +Point PerlinNoise::normal_vector(double x, double y) { + double n_x_y = noise(x, y, 0); + double n_dx_y = noise(x + 0.01, y, 0); + double n_x_dy = noise(x, y + 0.01, 0); + Point product = vector_product( + Point(0.01, 0, n_dx_y - n_x_y), + Point(0, 0.01, (n_x_dy - n_x_y)) + ); + return product; +} diff --git a/PerlinNoise.hpp b/PerlinNoise.hpp new file mode 100644 index 0000000..e013e9e --- /dev/null +++ b/PerlinNoise.hpp @@ -0,0 +1,23 @@ +/** + * Perlin Noise implementation for the ground (header file) + **/ +#include "Implicit.hpp" +#include +#include +#include +#include + +class PerlinNoise : public ImplicitSurface { + std::vector p; + public: + PerlinNoise(); + PerlinNoise(unsigned int seed); + double operator() (double _x, double _y, double _z) const; + double noise(double x, double y) const; + Point normal_vector(double x, double y); + private: + double noise(double x, double y, double z) const; + double fade(double t) const; + double lerp(double t, double a, double b) const; + double grad(int hash, double x, double y, double z) const; +}; diff --git a/main_ball.cpp b/main_ball.cpp index 00fb7c4..7ae31cc 100644 --- a/main_ball.cpp +++ b/main_ball.cpp @@ -10,8 +10,8 @@ using namespace std; int main(int argc, char** argv) { int i; - Point center(0,0,10); - Ball ball(center, 0, 0.25, 1, 1); + Point center(0,10,0); + Ball ball(center, 0, 0.25, 0, 1, 1); for(i=0; i< 10000; i++) { ball.update_pos(0.001); cout << ball << "\n"; diff --git a/spheroid.cpp b/spheroid.cpp index 4ac9fc6..f766838 100644 --- a/spheroid.cpp +++ b/spheroid.cpp @@ -4,18 +4,17 @@ #include "spheroid.hpp" -Spheroid::Spheroid(const Point& _center, double _p, double _q) : - ImplicitSurface(_center), init_p(_p), p(_p), q(_q), stiffness(0) { - _compute_volume(); - } +Spheroid::Spheroid(const Point& _center, double _min_p, double _p, double _q) : + ImplicitSurface(_center), normal_vector(Point(0,0,1)), min_p(_min_p), + init_p(_p), p(_p), q(_q), stiffness(0) +{ + _compute_volume(); +} void Spheroid::_compute_volume() { V = (4/3) * PI * p * q * q; } -void Spheroid::set_stiffness(size_t _stiffness) { - stiffness = _stiffness; -} void Spheroid::update_radius() { @@ -32,8 +31,8 @@ void Spheroid::update_center_pos(Point& _center) { } void Spheroid::check_horizontal_plan_collision(double& height) { - if ((center.z - p) <= height) { - p = fmin(init_p, center.z-height); + if ((center.y - p) <= height) { + p = fmin(init_p, center.y-height); update_radius(); } } @@ -51,3 +50,27 @@ void Spheroid::check_vertical_plan_collision(double& abscissa) { } } } + +Cuboid Spheroid::max_bounding_box() const { + double max_radius = sqrt((3/4) * V / PI / min_p); + double max_height = init_p; + Point _bd1(max_radius, max_radius, max_height); + Point _bd2(-max_radius, -max_radius, -max_height); + return Cuboid(_bd1, _bd2); +} + +void Spheroid::check_perlin_collision(PerlinNoise perlin) { + double height = perlin.noise(center.x, center.z); + if ((center.y - p) <= height) { + p = fmin(init_p, center.z- height ); + normal_vector = perlin.normal_vector(center.x, center.z); + update_radius(); + } +} + + +double Spheroid::operator() (double _x, double _y, double _z) const { + return (pow(_x, 2) / pow(q, 2) + + pow(_y, 2) / pow(q, 2) + + pow(_z, 2) / pow(p, 2) -1); +} diff --git a/spheroid.hpp b/spheroid.hpp index 8eb8ead..c1e051a 100644 --- a/spheroid.hpp +++ b/spheroid.hpp @@ -7,23 +7,22 @@ #include #include "Implicit.hpp" #include "common_structures.hpp" +#include "PerlinNoise.hpp" const double PI = 3.141592653589793; class Spheroid : public ImplicitSurface { public: - Spheroid(const Point& _center, double _p, double _q); + Spheroid(const Point& _center, double _min_p, double _p, double _q); void update_center_pos(Point& _center); void update_radius(); void update_height(); - void set_stiffness(size_t _stiffness); void check_horizontal_plan_collision(double& height); void check_vertical_plan_collision(double& abscissa); - double operator() (double _x, double _y, double _z) const { - return (pow(_x, 2) / pow(q, 2) - + pow(_y, 2) / pow(q, 2) - + pow(_z, 2) / pow(p, 2) -1); - } + Cuboid max_bounding_box() const; + void check_perlin_collision(PerlinNoise perlin); + Point getNormalVector() const { return normal_vector;} + double operator() (double _x, double _y, double _z) const; private: /** * p corresponds to the half-height of the ball, @@ -31,7 +30,8 @@ class Spheroid : public ImplicitSurface { * V is the volume. Extremely useful to have a constant volume in the * ball **/ - double init_p, p, q; + Point normal_vector; + double min_p, init_p, p, q; size_t stiffness; double V; void _compute_volume();