<?php
// Creates a virtual cube composed of polygons
$cube = new VirtualObject();
// Viewable screen dimensions
$width = 640;
$height = 480;
// Sets up the camera's orientation and its focal distance
$focal = 500;
array(-
$x,
0.
5, -
0.
5,
0),
);
// The vector normal to the viewing plane and parallel to the viewing direction
$n2[0][0] = $a[0][2];
$n2[1][0] = $a[1][2];
$n2[2][0] = $a[2][2];
$n2[3][0] = 0;
// Invert camera's plane to allow for change of basis
$a = inverse($a);
// Displace camera to its position in the world
$a[0][3] = 150;
$a[1][3] = 150;
$a[2][3] = 300 * $x;
// Create two images
$image1 = imagecreate($width, $height);
$image2 = imagecreate($width, $height);
// Set the line thickness of each image
imagesetthickness($image1, 1);
imagesetthickness($image2, 1);
// Set the background colors for each image
$blue1 = imagecolorallocate($image1, 0, 0, 127);
$blue2 = imagecolorallocate($image2, 0, 0, 127);
// Define some colors for each image
$white = imagecolorallocate($image1, 255, 255, 255);
$gray = imagecolorallocate($image2, 127, 127, 127);
// Draw each polygon
for($i = 0; $i < $cube->getPolyCount(); $i++){
// Retrieve the polygons from the cube object
$points = $cube->getPolygon($i);
// Modify each point of the polygon so that its now distanced to the camera's center point
for($j = 0; $j < 3; $j++){
$points[0][$j][0] -= $a[$j][3];
$points[1][$j][0] -= $a[$j][3];
$points[2][$j][0] -= $a[$j][3];
}
// Determine the normal vector for each polygon
$n1 = crossProduct(addition($points[0], scale(-1, $points[1])), addition($points[2], scale(-1, $points[1])));
// Write each vector in terms of the camera's orientation (change of basis)
$points[0] = multiply($a, $points[0]);
$points[1] = multiply($a, $points[1]);
$points[2] = multiply($a, $points[2]);
// Determine the distortion due to perspective
$focus[0] = $focal / magnitude($points[0]);
$focus[1] = $focal / magnitude($points[1]);
$focus[2] = $focal / magnitude($points[2]);
// Transform the 3d points into 2d coordinates for drawing
$x0 = $width / 2 + ($points[0][0][0] * $focus[0]);
$x1 = $width / 2 + ($points[1][0][0] * $focus[1]);
$x2 = $width / 2 + ($points[2][0][0] * $focus[2]);
$y0 = $height / 2 + ($points[0][1][0] * $focus[0]);
$y1 = $height / 2 + ($points[1][1][0] * $focus[1]);
$y2 = $height / 2 + ($points[2][1][0] * $focus[2]);
// Determine the cosine of the angle between the viewing plane and the polygonal plane
$cosTheta = dotProduct($n1, $n2) / (magnitude($n1) * magnitude($n2));
if($cosTheta <= 0){
// White lines because these are the planes at the front of the object
imageline($image1, $x0, $y0, $x1, $y1, $white);
imageline($image1, $x1, $y1, $x2, $y2, $white);
// imageline($image1, $x2, $y2, $x0, $y0, $white); // Draws the final polygon line
}else{
// Gray lines because these are the planes at the reare of the object
imageline($image2, $x0, $y0, $x1, $y1, $gray);
imageline($image2, $x1, $y1, $x2, $y2, $gray);
// imageline($image2, $x2, $y2, $x0, $y0, $gray); // Draws the final polygon line
}
}
// Make transparent the background of the viewable polygon drawing
imagecolortransparent($image1, $blue1);
// Layer it over the non-viewable polygon drawing
imagecopymerge($image2, $image1, 0, 0, 0, 0, 640, 480, 100);
// Output the finished image
imagepng($image2);
// Destroy the images
imagedestroy($image1);
imagedestroy($image2);
// Computes the cross product of two vectors
// $a: a row or column vector
// $b: a row or column vector
function crossProduct($a, $b){
if(sizeof($a) ==
1){ // Cross product of row vectors
return array( // Return the cross product of row vectors as a row vector
array( $a[0][1] *
$b[0][2] -
$a[0][2] *
$b[0][1],
-1 * ($a[0][0] * $b[0][2] - $a[0][2] * $b[0][0]),
$a[0][0] * $b[0][1] - $a[0][1] * $b[0][0],
0
)
);
}else{ // Cross product of column vectors
return array( // Return the cross product of column vectors as a column vector
array($a[1][0] *
$b[2][0] -
$a[2][0] *
$b[1][0]),
array(-
1 *
($a[0][0] *
$b[2][0] -
$a[2][0] *
$b[0][0])),
array($a[0][0] *
$b[1][0] -
$a[1][0] *
$b[0][0]),
);
}
}
// Computes the addition of two matrices
// $A: an m x n matrix
// $B: an m x n matrix
function addition($A, $B){
$M; // The added matrix
// Add the two matrices together
for($i =
0;
$i <
sizeof($A);
$i++
){
for($j =
0;
$j <
sizeof($A[0]);
$j++
){
$M[$i][$j] = $A[$i][$j] + $B[$i][$j];
}
}
return $M; // Return the added matrix
}
// Computes a random matrix
// $m: the row dimension
// $n: the column dimension
// $lower: the lower bound of random numbers
// $upper: the upper bound of random numbers
function randMatrix($m, $n, $lower, $upper){
$M; // A random matrix
// Generate the random matrix
for($i = 0; $i < $m; $i++){
for($j = 0; $j < $n; $j++){
$M[$i][$j] =
rand($lower,
$upper);
}
}
return $M; // Return the random matrix
}
// Computes the magnitude of a vector
// $a: a row or column vector
function magnitude($a){
$result = 0; // The magnitude of the vector
// Use the Pythagorean theorem to determine the vector's magnitude
for($i =
0;
$i <
sizeof($a);
$i++
){
for($j =
0;
$j <
sizeof($a[0]);
$j++
){
$result +=
pow($a[$i][$j],
2);
}
}
return sqrt($result);
// Return the magnitude of the vector
}
// Computes the adjoint of a matrix
// $A: a square matrix
function adjoint($A){
return scale(determinant($A), inverse($A)); // Returns the adjoint of a matrix
}
// Computes a scaled matrix
// $k: a scalar number
// $A: an m x n matrix
function scale($k, $A){
// Scale the matrix by multiplying each entry by k
for($i =
0;
$i <
sizeof($A);
$i++
){
for($j =
0;
$j <
sizeof($A[0]);
$j++
){
$A[$i][$j] *= $k;
}
}
return $A; // Returns the scaled matrix
}
// Computes the determinant of a matrix
// $A: a square matrix
function determinant($A){
$determinant = 1; // The determinant of the matrix
$n =
sizeof($A);
// Dimension of the square matrix
$E = identity($n); // An elementary matrix
// Find the determinant of a matrix by performing elementary matrix operations
// on an augmented matrix through the use of elementary matrices in order
// to convert the matrix into upper triangular form
// Multiply the diagonals of the upper triangular matrix to arrive at the
// determinant, only elementary operations I and III are allowed on the matrix.
// If operation I is performed at any time, multiply the determinant by a -1.
for($j = 0; $j < $n; $j++){
for($i = $j; $i < $n; $i++){
if($i == $j){
if($A[$i][$j] == 0){
for($k = $j + 1; $k < $n; $k++){
if($A[$k][$j] != 0){
$swap = $A[$i];
$A[$i] = $A[$k];
$A[$k] = $swap;
$determinant *= -1;
$k = $n;
}
}
}
$determinant *= $A[$i][$j];
}else{
$E[$i][$j] = -$A[$i][$j] / $A[$j][$j];
}
$A = multiply($E, $A);
$E = identity($n);
}
}
return $determinant; // Return the determinant of the matrix
}
// Computes the inverse of a matrix
// $A: a square matrix
function inverse($A){
$n =
sizeof($A);
// Dimension of the square matrix
$V = identity($n); // The inverse of the matrix
$E = identity($n); // An elementary matrix
// Find the inverse matrix by performing elementary matrix operations
// on an augmented matrix through the use of elementary matrices
for($j = 0; $j < $n; $j++){
for($i = $j; $i < $n; $i++){
if($i == $j){
if($A[$i][$j] == 0){
for($k = $j + 1; $k < $n; $k++){
if($A[$k][$j] != 0){
$swap = $A[$i];
$A[$i] = $A[$k];
$A[$k] = $swap;
$swap = $V[$i];
$V[$i] = $V[$k];
$V[$k] = $swap;
$k = $n;
}
}
}
$E[$i][$j] = 1 / $A[$i][$j];
}else{
$E[$i][$j] = -$A[$i][$j];
}
$A = multiply($E, $A);
$V = multiply($E, $V);
$E = identity($n);
}
}
for($j = $n - 1; $j > 0; $j--){
for($i = $j - 1; $i > -1; $i--){
$E[$i][$j] = -$A[$i][$j];
$A = multiply($E, $A);
$V = multiply($E, $V);
$E = identity($n);
}
}
return $V; // Return the inverse matrix
}
// Computes the product of a matrix multiplication
// $A: An m x n matrix
// $B: An n x o matrix
function multiply($A, $B){
$M; // The product of the multiplication
$B = transpose($B); // Transpose the second matrix
// Do the multiplication by making use of the dot product
for($i =
0;
$i <
sizeof($A);
$i++
){
for($j =
0;
$j <
sizeof($B);
$j++
){
$M[$i][$j] = dotProduct
(array($A[$i]),
array($B[$j]));
}
}
return $M; // Return the product
}
// Computes the dot product of two vectors
// $a: a row or column vector
// $b; a row or column vector
function dotProduct($a, $b){
$result = 0; // The result of the dot product
// The dot product
for($i =
0;
$i <
sizeof($a);
$i++
){
for($j =
0;
$j <
sizeof($a[0]);
$j++
){
$result += $a[$i][$j] * $b[$i][$j];
}
}
return $result; // Return the dot product
}