array( array( array(-1, 0,-0.5), array(0.8,0.4,0.1) ), array( array( 1,-1,-0.5), array( 1, 1, 1) ), array( array( 0,-1, 0), array(0.1,0.2,0.5) ) ) ); //sphere data: , , , $spheres = array (); if ($s1 == 1) { $sphere = array( array( array(-1.05, 0 ,4), array(1 ,0.5), array(1 , 0.5,0.25), array(40,0.8) ) ); $spheres = $sphere; } if ($s2 == 1) { $sphere = array( array( array( 1.05, 0 ,4), array(1 ,0.5), array(0.5 , 1 ,0.5 ), array(40,0.8) ) ); $spheres = array_merge($spheres,$sphere); } if ($s3 == 1) { $sphere = array( array( array( 0 , 3 ,5), array(2 ,0.5), array(0.25, 0.5,1 ), array(30,0.4) ) ); $spheres = array_merge($spheres,$sphere); } if ($s4 == 1) { $sphere = array( array( array(-1 ,-2.3,9), array(2 ,0.5), array(0.5 , 0.3,0.1 ), array(30,0.4) ) ); $spheres = array_merge($spheres,$sphere); } if ($s5 == 1) { $sphere = array( array( array( 1.3 ,-2.6,9), array(1.8,0.5), array(0.1 , 0.3,0.5 ), array(30,0.4) ) ); $spheres = array_merge($spheres,$sphere); } $spheres_test = array ( "spheres" => $spheres ); $ambient_test = array( "ambient" => array( 0.2,0.2,0.2 ) ); $camera_test = array( "camera" => array( 0,0,-3 ) ); $test_scene = array_merge($lights_test, $spheres_test, $ambient_test, $camera_test); $new_scene = array ( "lights" => array( array( array(-1,0,-0.5), array(0.8,0.4,0.1) ), array( array( 1,1,-0.5), array(1 ,1 ,1 ) ), array( array( 0,1, 0 ), array(0.1,0.2,0.5) ) ), "spheres" => array ( array( array( 1, 0,4), array(0.5,0), array(1,0,0), array(40,0.8) ), array( array(-1, 0,4), array(0.5,0), array(0,1,0), array(40,0.8) ), array( array( 0, 1,3), array(0.5,0), array(0,0,1), array(40,0.8) ), array( array( 0,-1,3), array(0.5,0), array(1,1,1), array(40,0.8) ) ), "ambient" => array( 0.2,0.2,0.2 ), "camera" => array( 0,0,-3 ) ); $scene = $test_scene; $obj_Amnt = count( $scene[spheres] ); $light_Amnt = count( $scene[lights] ); $ind = 0; while( $ind < $light_Amnt ) { //normalize included light vector directions. $nv_val = v_norm( $scene[lights][$ind][0]); $scene[lights][$ind][0] = $nv_val; $ind += 1; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //=== vector operations - (vectors are represented by three element arrays) =================== //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //--- vector addition --- function v_add( $inp1, $inp2 ){ //input is two three element arrays, output is one three element array. return $output = array( ($inp1[0]+$inp2[0]), ($inp1[1]+$inp2[1]), ($inp1[2]+$inp2[2]) ); } //--- vector subtraction --- function v_sub( $inp1, $inp2 ){ //input is two three element arrays, output is one three element array. return $output = array( ($inp1[0]-$inp2[0]), ($inp1[1]-$inp2[1]), ($inp1[2]-$inp2[2]) ); } //--- vector multiplication --- //used in diffuse section, seems to do what it's supposed to do. function v_mult( $inp1, $inp2 ){ return $output = array( ($inp1[0]*$inp2[0]), ($inp1[1]*$inp2[1]), ($inp1[2]*$inp2[2]) ); } //--- scalar multiplication --- function v_scalarMult( $inp1, $inp2 ){ //input is a three element array and a scaler, output is one three element array. return $output = array( ($inp1[0]*$inp2), ($inp1[1]*$inp2), ($inp1[2]*$inp2) ); } //--- scalar division --- function v_scalarDiv( $inp1, $inp2 ){ //input is a three element array and a scaler, output is one three element array. return $output = array( ($inp1[0]/$inp2), ($inp1[1]/$inp2), ($inp1[2]/$inp2) ); } //--- cross product --- function v_cross( $inp1, $inp2 ){ //input is two three element arrays, output is one three element array. return $output = array( ($inp1[1]*$inp2[2] - $inp2[1]*$inp1[2]), ($inp1[2]*$inp2[0] - $inp2[2]*$inp1[0]), ($inp1[0]*$inp2[1] - $inp2[0]*$inp1[1]) ); } //--- dot product --- function v_dot( $inp1, $inp2 ){ //input is two three element arrays, scaler output. return $output = ($inp1[0]*$inp2[0] + $inp1[1]*$inp2[1] + $inp1[2]*$inp2[2]); } //--- length of vector --- function v_length( $inp ){ //input is a three element array, scaler output. return $output = sqrt( pow( $inp[0],2) + pow($inp[1],2) + pow($inp[2],2) ); } //--- normalize vector --- function v_norm( $inp ){ //input is a three element array, output is one three element array. $v_dist = v_length( $inp ); return $output = array( ($inp[0]/$v_dist), ($inp[1]/$v_dist), ($inp[2]/$v_dist) ); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //=== ray-sphere intersection ================================================================= //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //sphere data: , , , function calcRaySphereIntersection( $P, $D, $sphereInd ){ //starting point, ray direction, sphere index global $scene; $C = $scene[spheres][$sphereInd][0]; //--- sphere center. $V = v_sub( $P, $C ); $R = $scene[spheres][$sphereInd][1][0]; //--- radius of sphere. $DV = v_dot( $D, $V ); $D2 = v_dot( $D, $D ); $SQ = $DV*$DV - $D2*(v_dot($V,$V)-$R*$R); if ($SQ <= 0){ $output = -1; } else { $SQ = sqrt($SQ); $T1 = (-$DV+$SQ)/$D2; $T2 = (-$DV-$SQ)/$D2; $output = min( $T1, $T2 ); } return $output; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //=== ray-tracing function ==================================================================== //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ function Trace( $P, $D, $reclev ){ // starting point, ray direction, and recursion level. global $max_Dist, $obj_Amnt, $light_Amnt, $max_RecLev, $scene, $Specular_test, $Diffuse_test, $Reflection_test; $minT = $max_Dist; $closest = $obj_Amnt; // Find closest intersection: $ind = 0; while( $ind < $obj_Amnt) { $T = calcRaySphereIntersection( $P, $D, $ind ); if (($T > 0) and ($T < $minT)) { $minT = $T; $closest = $ind; } $ind += 1; } $ind = 0; // If not found, return background color: if ($closest == $obj_Amnt) { $Pixel = $bg_Color; //$Pixel = array(dechex(rand(0,127)+rand(0,127)), dechex(rand(0,127)+rand(0,127)), dechex(rand(0,127)+rand(0,127))); } else // Else calculate the color of the intersection point: { $IP = v_add( $P, v_scalarMult($D,$minT) ); $R = $scene[spheres][$closest][1][0]; $Normal = v_scalarDiv( v_sub($IP,$scene[spheres][$closest][0]),$R ); $V = v_sub( $P, $IP ); $Refl = v_sub( v_scalarMult($Normal,2*v_dot($Normal,$V)), $V ); // Lighting: $Pixel = $scene[ambient]; $ind = 0; while ($ind < $light_Amnt) { $Light = $scene[lights][$ind][0]; // Shadowtest: $Shadowed = false; $ind2 = 0; while ($ind2 < $obj_Amnt) { if (($ind2 != $closest) and (calcRaySphereIntersection($IP,$Light,$ind2) > 0)) { $Shadowed = true; $ind2 = $obj_Amnt; } $ind2 += 1; } if ($Shadowed == false) { if ($Diffuse_test == 1) // Diffuse lighting: { $Factor = v_dot($Normal, $Light); if ($Factor > 0) { $Pixel = v_add( $Pixel, v_scalarMult( v_mult($scene[lights][$ind][1],$scene[spheres][$closest][2]),$Factor ) ); } } if ($Specular_test == 1) // Specular highlights: { $Factor = v_dot( v_norm($Refl), $Light ); if ($Factor > 0) { $Pixel = v_add( $Pixel, v_scalarMult( $scene[lights][$ind][1],(pow($Factor,$scene[spheres][$closest][3][0])*$scene[spheres][$closest][3][1]))); } } } //if(!Shadowed) $ind += 1; } //while($ind < $light_Amnt) if ($Reflection_test == 1) // Reflections: { if (($recLev < $max_RecLev) and ($scene[spheres][$closest][1][1] > 0)) { $Pixel = v_add( $Pixel,v_scalarMult( Trace($IP, $Refl, $recLev+1), $scene[spheres][$closest][1][1] ) ); } } } //else return $Pixel; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //=== calculating the image --- also display image ============================================ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ if ($Output_type == "Table") { print("
\n"); print(""); print("\n"); } elseif ($Output_type == "Jpeg") { Header("Content-Type: image/jpeg"); $renderR = imagecreate ( $image_Width,$image_Height ) or die ("Cannot Initialize new GD image stream"); //greyscale image... $ind = 0; while ($ind < 256) { imagecolorallocate ($renderR, $ind,$ind,$ind ); $ind += 1; } } $image_data = array(); $indY = 0; while ($indY < $image_Height) { $coordY = $indY/($image_Height-1)*2-1; $indX = 0; while ($indX < $image_Width) { $coordX = ($indX/($image_Width-1)-0.5)*2*$image_Width/$image_Height; $Pf = Trace( $scene[camera], array( $coordX,$coordY, 3), 1); array_push( $image_data, $Pf_rgb ); if ($Output_type == "Table") { print(""); } elseif ($Output_type == "Jpeg") { $color = (int)((min( round($Pf[0]*256),255 ) + min( round($Pf[1]*256),255 ) + min( round($Pf[2]*256),255 ))/3); imagesetpixel ( $renderR,$indX,$indY, $color ); } $indX += 1; } if ($Output_type == "Table") { print(""); } $indY += 1; } if ($Output_type == "Table") { print("
"); print("    
\n"); print("
\n"); ?>
>middle left sphere
>middle right sphere
>bottom sphere
>top left sphere
>top right sphere

>specular highlights
>diffuse lighting
>reflections