diff --git a/Ball.cpp b/Ball.cpp index 1e24fdc..8b2060e 100644 --- a/Ball.cpp +++ b/Ball.cpp @@ -2,7 +2,7 @@ #include #include -Ball::Ball(Point& _center, double _min_height, double _v_x, double _p, double _q) : +Ball::Ball(Point& _center, double _min_height, double _v_x, double _v_z, double _p, double _q) : Center(_center), surface(_center, min_height, _p, _q), init_h(_center.y), @@ -13,13 +13,15 @@ Ball::Ball(Point& _center, double _min_height, double _v_x, double _p, double _q B(0), U(sqrt(2 * G_CTE * _center.y)), T(sqrt(2.0 * _center.y / G_CTE)), - v_x(_v_x) + v_x(_v_x), + v_z(_v_z) { } void Ball::_compute_pos(double dt) { 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); } @@ -39,19 +41,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 << ":"; diff --git a/Ball.hpp b/Ball.hpp index 0ab1a86..1bc5d5b 100644 --- a/Ball.hpp +++ b/Ball.hpp @@ -24,15 +24,16 @@ 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(Point& _center, double _min_height, double _v_x, double p, double q); + Ball(Point& _center, double _min_height, double _v_x, 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 c816215..aff6c53 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 14e6f58..7ae31cc 100644 --- a/main_ball.cpp +++ b/main_ball.cpp @@ -11,7 +11,7 @@ using namespace std; int main(int argc, char** argv) { int i; Point center(0,10,0); - Ball ball(center, 0, 0.25, 1, 1); + 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 1e5be43..d55f451 100644 --- a/spheroid.cpp +++ b/spheroid.cpp @@ -4,8 +4,8 @@ #include "spheroid.hpp" -Spheroid::Spheroid(Point& _center, double _min_p, size_t _p, size_t _q) : - ImplicitSurface(_center), min_p(_min_p), init_p(_p), p(_p), q(_q) { +Spheroid::Spheroid(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(); } @@ -56,3 +56,19 @@ Cuboid Spheroid::max_bounding_box() const { 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 - center.x, 2) / pow(q, 2) + + pow(_y - center.y, 2) / pow(q, 2) + + pow(_z - center.z, 2) / pow(p, 2) -1); +} diff --git a/spheroid.hpp b/spheroid.hpp index eb0128d..b4576a3 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(Point& _center, double _min_p, size_t _p, size_t _q); + Spheroid(Point& _center, double _min_p, double _p, double _q); void update_center_pos(Point& _center); void update_radius(); void update_height(); void check_horizontal_plan_collision(double& height); void check_vertical_plan_collision(double& abscissa); Cuboid max_bounding_box() const; - double operator() (double _x, double _y, double _z) const { - return (pow(_x - center.x, 2) / pow(q, 2) - + pow(_y - center.y, 2) / pow(q, 2) - + pow(_z - center.z, 2) / pow(p, 2) -1); - } + 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,9 @@ class Spheroid : public ImplicitSurface { * V is the volume. Extremely useful to have a constant volume in the * ball **/ + Point normal_vector; double min_p, init_p, p, q; + size_t stiffness; double V; void _compute_volume(); };