📜 ⬆️ ⬇️

Particle System for PHP in 3D

Since childhood, I have a cherished programming dream - to write a physics engine. As befits a dream, I never came close to her. But once a couple of nights stood out when I was supposed to be on duty in the room, and I had a laptop with me.
In general, I took to simulate the movement and collision of particles on PHP. Why PHP? Because it is the only language in which I can freely express my programming thoughts. In general, the coordinates were first displayed in the console, then began to take graphic images. The thought to generate animation immediately appeared ...
image


Googling, I found an old class GIFEncoder v.2 , which allowed me to collect frames in the film! I was very encouraged, and I continued the experiments.
The very first, difficult and main problem was the addition of impulses. The fact is that with a simple movement of a particle on X, for example, 1, and the same Y, the particles scattered in all 360 sides did not want to form a circle - they stubbornly lined up in a rhombus. I didn’t learn algebra badly, but I was interested in improvising, experimenting with coefficients.
The second problem was the projection of the scattered in 3D points on the plane. Since I taught geometry no better than algebra, improvised coefficients helped me out: it would not be easy to choose a more or less plausible projection with the correct ones. Anyway, the enthusiasm was enough to create a script that generates the above movie. And the mechanism is best explained directly in the code. You should read and understand PHP freely:
<?php //    ,      =) set_time_limit(0); //   $start = microtime(1); // GIFEncoder  : // http://saintist.ru/2009/05/12/316/ include('gif_animate.php'); //     class space { //   public $points = array(); //   -  //       private $x; private $y; private $z; // . .  step. public $steps = 0; public function __construct($x, $y, $z) { $this -> x = $x; $this -> y = $y; $this -> z = $z; } // -  ... public function addPoint($point, $x, $y, $z, $fx = 0, $fy = 0, $fz = 0) { array_push($this -> points, array($point, $x, $y, $z)); $point -> addP($fx, $fy, $fz); } // .  ,     . //  -  ,    . //   (  -   )     , //    . ,    =    // ,     < 1. // , 1  =     1  1   . //       . public function step() { //      $t = 1; //   . //    ,   . $busy = array(); //     space       //     foreach ($this -> points as $n => &$point) { $x = $point[1]; $y = $point[2]; $z = $point[3]; //      -  ,    if (!($x >= 0 && $x < $this->x && $y >= 0 && $y < $this->y && $z >= 0 && $z < $this->z)) { unset($this->points[$n]); continue; } //       $f = abs($point[0]->p['fx']) + abs($point[0]->p['fy']) + abs($point[0]->p['fz']); //    ,     1   $t if ($f > 0 && 1 / $f < $t) { //      $t = 1 / $f; } } //  .  . foreach ($this -> points as $n => &$point) { $xyz = abs($point[0]->p['fx']) + abs($point[0]->p['fy']) + abs($point[0]->p['fz']); //        $hypo = pow(abs($point[0]->p['fx']), 2) + pow(abs($point[0]->p['fy']), 2) + pow(abs($point[0]->p['fz']), 2); //   $move_x -  ,      . //   . //    X  Y  ,  Z -    //     X  Y, . if ($point[0]->p['fx'] != 0 && $xyz > 0) { if ($point[0]->p['fx'] < 0) { $fxmin = 1; } $move_x = sqrt($hypo) * ($point[0]->p['fx'] / $xyz); if (isset($fxmin)) $move_x = $move_x * -1; } else { $move_x = 0; } if ($point[0]->p['fy'] != 0 && $xyz > 0) { if ($point[0]->p['fy'] < 0) { $fymin = 1; } $move_y = sqrt($hypo) * ($point[0]->p['fy'] / $xyz); if (isset($fymin)) $move_y = $move_y * -1; } else { $move_y = 0; } if ($point[0]->p['fz'] != 0 && $xyz > 0) { if ($point[0]->p['fz'] < 0) { $fzmin = 1; } $move_z = sqrt($hypo) * ($point[0]->p['fz'] / $xyz); if (isset($fzmin)) $move_z = $move_z * -1; } else { $move_z = 0; } //        $point[1] += $move_x*$t; $point[2] += $move_y*$t; $point[3] += $move_z*$t; } $this -> steps+=$t; } //    space  GIF public function shot() { $r = imagecreatetruecolor($this -> x+1, $this -> y+1); // ,   foreach ($this -> points as &$point) { $x = $point[1]; $y = $point[2]; $z = $point[3]; if ($x >= 0 && $x < $this->x && $y >= 0 && $y < $this->y && $z >= 0 && $z < $this -> z) { // ,  .  ,  ,    Z //   ,     -  Z. $ox = $this->x / 2; $oy = $this->y / 2; $oz = $this->z / 2; $xf = $x - $ox; $yf = $y - $oy; $zf = $z; $xr = $x - $xf / ($this->z/($this->z - $z)); $yr = $y - $yf / ($this->z/($this->z - $z)); imageline($r, $xr, $yr, $xr, $yr, $point[0]->color); } } ob_start(); imagegif($r); return ob_get_clean(); } } class Point { public $p = array('fx' => 0, 'fy' => 0, 'fz' => 0); public $color; //     public function __construct() { $red = dechex(rand(1, 255)); if (strlen($red) < 2) $red = '0'.$red; $green = dechex(rand(1, 255)); if (strlen($green) < 2) $green = '0'.$green; $blue = dechex(rand(1, 255)); if (strlen($blue) < 2) $blue = '0'.$blue; $this->color = hexdec("0x$red$green$blue"); } public function addP($fx = 0, $fy = 0, $fz = 0) { $this->p['fx'] += $fx; $this->p['fy'] += $fy; $this->p['fz'] += $fz; } } $gifs = array(); // GD- GIF-,     $space = new space(399, 399, 399, false, true); //     . //      ,     $rands = range(-10, 10, 0.5); for ($i=0; $i<1000; $i++) { // ...    $space->addPoint(new Point, 200, 200, 200, $rands[array_rand($rands)], $rands[array_rand($rands)], $rands[array_rand($rands)]); } //   100      ... while($space->steps < 100) { $nshot = $space -> steps; $space -> step(); if ((int)$nshot < (int)$space -> steps) { array_push($gifs, $space -> shot()); echo 'Step #',$space -> steps,"\r\n"; } } //    ... $gif = new GIFEncoder($gifs, 0, 0, 0, 0, 0, 0, 'bin'); file_put_contents('c:\anim.gif', $gif -> GetAnimation()); echo "\r\nTime: ",substr(microtime(1) - $start, 0, 4); //   :-) 

The principle is clear to you. One of the first videos was this:
image
Then in 3D, this one:
image
Rave? Maybe. But do not be afraid to implement the most delusional ideas. This is the best way to learn to think in a programming language.

')

Source: https://habr.com/ru/post/115791/


All Articles