public function sub(Image_3D_Vector $vector) { $this->_x -= $vector->getX(); $this->_y -= $vector->getY(); $this->_z -= $vector->getZ(); $this->_length = null; }
public function getAngle(Image_3D_Vector $vector) { $length = $vector->length() * $this->length(); if ($length < 0.0001) { return 1; } return abs(acos($this->scalar($vector) / $length) / M_PI - 0.5) * 2; }
public function getColor(Image_3D_Interface_Enlightenable $polygon) { $color = clone $polygon->getColor(); $light = new Image_3D_Vector($this->_x, $this->_y, $this->_z); $light->sub($polygon->getPosition()); $light->unify(); $light->add(new Image_3D_Vector(0, 0, -1)); $normale = $polygon->getNormale(); $angle = abs(1 - $normale->getAngle($light)); $color->addLight($this->_color, $angle); return $color; }
public function getColor(Image_3D_Interface_Enlightenable $polygon) { $color = clone $polygon->getColor(); // Create vector from polygons point to light source $light = new Image_3D_Vector($this->_x, $this->_y, $this->_z); $light->sub($polygon->getPosition()); // Create vector from polygons point to camera // $camera = new Image_3D_Vector(0, 0, -100); // $camera->sub($polygon->getPosition()); // Compare with polygones normale vector $normale = $polygon->getNormale(); $angle = $normale->getAngle($light); // Use angle as light intensity $color->addLight($this->_color, $angle); return $color; }
public function getColor(Image_3D_Interface_Enlightenable $polygon) { $color = clone $polygon->getColor(); $light = new Image_3D_Vector($this->_x, $this->_y, $this->_z); $light->sub($polygon->getPosition()); $distance = $light->length(); if ($distance > $this->_distance) { return $color; } $factor = 1 - pow($distance / $this->_distance, $this->_falloff); $light->unify(); $light->add(new Image_3D_Vector(0, 0, -1)); $normale = $polygon->getNormale(); $angle = abs(1 - $normale->getAngle($light)); $color->addLight($this->_color, $angle * $factor); return $color; }
public function getColor(Image_3D_Interface_Enlightenable $polygon) { $color = clone $polygon->getColor(); $light = new Image_3D_Vector($this->_x, $this->_y, $this->_z); $light->sub($polygon->getPosition()); $light->unify(); $angle = $light->getAngle($this->_direction); if ($angle > $this->_angle) { return $color; } if ($this->_float) { $factor = 1 - pow($angle / $this->_angle, $this->_float); } else { $factor = 1; } $light->add(new Image_3D_Vector(0, 0, -1)); $normale = $polygon->getNormale(); $angle = abs(1 - $normale->getAngle($light)); $color->addLight($this->_color, $angle * $factor); return $color; }
protected function _sendRay(Image_3D_Line $ray, $depth) { if ($depth <= 0) { return false; } $lowest = 1000; $nearest = false; foreach ($this->_polygones as $nr => $polygon) { $t = $polygon->distance($ray); if ($t === false) { continue; } if ($t < $lowest) { $nearest = $nr; $lowest = $t; } } if ($nearest === false) { return false; } // Examine cutting point $cuttingPoint = clone $ray; $direction = $cuttingPoint->getDirection(); $cuttingPoint->add($cuttingPoint->getDirection()->multiply($lowest)); // Create point to use for enlightenment $point = new Image_3D_Point($cuttingPoint->getX(), $cuttingPoint->getY(), $cuttingPoint->getZ()); $point->addVector($this->_polygones[$nearest]->getNormale()); $point->addColor($this->_polygones[$nearest]->getColor()); // Perhaps send new rays $transparency = end($this->_polygones[$nearest]->getColor()->getValues()); $reflection = $this->_polygones[$nearest]->getColor()->getReflection(); if ($reflection > 0) { // Calculate reflection vector $normale = $this->_polygones[$nearest]->getNormale(); $normale->unify(); $direction = $ray->getDirection(); $reflectionRay = new Image_3D_Line($cuttingPoint->getX(), $cuttingPoint->getY(), $cuttingPoint->getZ(), $direction->sub($normale->multiply($normale->scalar($direction))->multiply(2))); $reflectionColor = $this->_sendRay($reflectionRay, $depth - 1); if ($reflectionColor === false) { $reflectionColor = $this->_background; } $reflectionColor->mixAlpha($reflection); $point->addColor($reflectionColor); } if ($transparency > 0) { // Calculate colors in the back of our polygon $transparencyRay = new Image_3D_Line($cuttingPoint->getX(), $cuttingPoint->getY(), $cuttingPoint->getZ(), $ray->getDirection()); $transparencyColor = $this->_sendRay($transparencyRay, $depth - 1); if ($transparencyColor === false) { $transparencyColor = $this->_background; } $transparencyColor->mixAlpha($transparency); $point->addColor($transparencyColor); } // Check lights influence for cutting point $pointLights = array(); foreach ($this->_lights as $light) { // Check for shadow casting polygones if ($this->_shadows) { // Create line from point to light source $lightVector = new Image_3D_Vector($light->getX(), $light->getY(), $light->getZ()); $lightVector->sub($cuttingPoint); $lightVector = new Image_3D_Line($cuttingPoint->getX(), $cuttingPoint->getY(), $cuttingPoint->getZ(), $lightVector); // Check all polygones for possible shadows to cast $modifyingPolygones = array(); $modifyLight = false; foreach ($this->_polygones as $polygon) { $t = $polygon->distance($lightVector); // $t > 1 means polygon is behind the light, but crosses the ray if ($t !== false && $t < 1) { $transparency = end($polygon->getColor()->getValues()); if ($transparency > 0) { // Polygon modifies light source $modifyingPolygones[] = $polygon; $modifyLight = true; } else { // Does not use lightsource when non transparent polygon is in its way continue 2; } } } // We only reach this code with no, or only transparent polygones if ($modifyLight) { $light = clone $light; $lightColor = $light->getRawColor()->getValues(); // Modify color for all polygones in the rays way to earth foreach ($modifyingPolygones as $polygon) { $polygonColor = $polygon->getColor()->getValues(); $lightColor[0] *= $polygonColor[0] * (1 - $polygonColor[3]); $lightColor[1] *= $polygonColor[1] * (1 - $polygonColor[3]); $lightColor[2] *= $polygonColor[2] * (1 - $polygonColor[3]); $lightColor[3] *= $polygonColor[3]; } $light->setColor(new Image_3D_Color($lightColor[0], $lightColor[1], $lightColor[2], $lightColor[3])); } } $pointLights[] = $light; } $point->calculateColor($pointLights); return $point->getColor(); }
public function __toString() { return parent::__toString() . ' -> ' . $this->getDirection()->__toString(); }
public function distance(Image_3D_Line $line) { // Calculate parameters for plane $normale = $this->getNormale(); $A = $normale->getX(); $B = $normale->getY(); $C = $normale->getZ(); $D = -($normale->getX() * $this->_points[0]->getX() + $normale->getY() * $this->_points[0]->getY() + $normale->getZ() * $this->_points[0]->getZ()); // Calculate wheather and where line cuts the polygons plane $lineDirection = $line->getDirection(); $denominator = -($A * $line->getX() + $B * $line->getY() + $C * $line->getZ() + $D); $numerator = $A * $lineDirection->getX() + $B * $lineDirection->getY() + $C * $lineDirection->getZ(); // Nu cut, when denomintor equals 0 (parallel plane) if ((int) ($denominator * 100000) === 0) { return false; } if ((int) ($numerator * 100000) === 0) { return false; } $t = $denominator / $numerator; // No cut, when $t < 0 (plane is behind the camera) if ($t <= 0) { return false; } // TODO: Perhaps add max distance check with unified normale vector // Calculate cutting point between line an plane $cuttingPoint = $line->calcPoint($t); // Perform fast check for point in bounding cube; if ($cuttingPoint->getX() < $this->_boundingRect[0] || $cuttingPoint->getY() < $this->_boundingRect[1] || $cuttingPoint->getZ() < $this->_boundingRect[2] || $cuttingPoint->getX() > $this->_boundingRect[3] || $cuttingPoint->getY() > $this->_boundingRect[4] || $cuttingPoint->getZ() > $this->_boundingRect[5]) { return false; } // perform exact check for point in polygon $lastScalar = 0; foreach ($this->_points as $nr => $point) { $nextPoint = $this->_points[($nr + 1) % count($this->_points)]; $edge = new Image_3D_Vector($nextPoint->getX() - $point->getX(), $nextPoint->getY() - $point->getY(), $nextPoint->getZ() - $point->getZ()); $v = new Image_3D_Vector($cuttingPoint->getX() - $point->getX(), $cuttingPoint->getY() - $point->getY(), $cuttingPoint->getZ() - $point->getZ()); $scalar = $edge->crossProduct($v)->scalar($normale); if ($scalar * $lastScalar >= 0) { $lastScalar = $scalar; } else { return false; } } // Point is in polygon, return distance to polygon return $t; }