Created
September 6, 2012 23:50
-
-
Save usrlocalben/3661517 to your computer and use it in GitHub Desktop.
raymarch in php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// oh boy, lets raymarch in php. | |
function LERP( $a, $b, $t ) { return (1.0-$t)*$a + $t*$b; } | |
function CLAMP($a,$x,$y){ return ($a<$x?$x:($a>$y?$y:$a)); } | |
function CLAMP01($a) { return CLAMP($a,0.0,1.0); } | |
class vec3 { | |
public $x,$y,$z; | |
public function __construct($a,$b,$c) { $this->x = $a; $this->y = $b; $this->z = $c; } | |
//public function __construct($a){ $x = $y = $z = $w = $a; } | |
//public function __construct(){ $x=$y=$z=$w=0;} | |
public function add_vec3(vec3 $v) { return new vec3( $this->x + $v->x ,$this->y + $v->y ,$this->z + $v->z ); } | |
public function sub_vec3(vec3 $v) { return new vec3( $this->x - $v->x ,$this->y - $v->y ,$this->z - $v->z ); } | |
public function mul_vec3(vec3 $v) { return new vec3( $this->x * $v->x ,$this->y * $v->y ,$this->z * $v->z ); } | |
public function div_vec3(vec3 $v) { return new vec3( $this->x / $v->x ,$this->y / $v->y ,$this->z / $v->z ); } | |
public function add_num($v) { return new vec3( $this->x + $v ,$this->y + $v ,$this->z + $v ); } | |
public function sub_num($v) { return new vec3( $this->x - $v ,$this->y - $v ,$this->z - $v ); } | |
public function mul_num($v) { return new vec3( $this->x * $v ,$this->y * $v ,$this->z * $v ); } | |
public function div_num($v) { return new vec3( $this->x / $v ,$this->y / $v ,$this->z / $v ); } | |
public function add($v) { if ( $v instanceof vec3 ) return $this->add_vec3($v); return $this->add_num($v); } | |
public function sub($v) { if ( $v instanceof vec3 ) return $this->sub_vec3($v); return $this->sub_num($v); } | |
public function mul($v) { if ( $v instanceof vec3 ) return $this->mul_vec3($v); return $this->mul_num($v); } | |
public function div($v) { if ( $v instanceof vec3 ) return $this->div_vec3($v); return $this->div_num($v); } | |
public function dot(vec3 $v) { return $this->x*$v->x + $this->y*$v->y + $this->z*$v->z; } | |
public function length() { return sqrt($this->dot($this)); } | |
public function normalized() { return $this->div_num( $this->length() ); } | |
public function dump(){ | |
printf("(%11.4f,%11.4f,%11.4f)\n",$this->x,$this->y, $this->z); | |
} | |
public static function lerp(vec3 $a, vec3 $b, $t ) { | |
return new vec3( | |
LERP($a->x, $b->x, $t) | |
,LERP($a->y, $b->y, $t) | |
,LERP($a->z, $b->z, $t) ); | |
} | |
public static function nlerp(vec3 $a, vec3 $b, $t ) { | |
return static::lerp($a,$b,$t)->normalized(); | |
} | |
public static function saturate(vec3 $a) { | |
return new vec3( CLAMP01($a->x), CLAMP01($a->y), CLAMP01($a->z) ); | |
} | |
public function truecolor32() { | |
// printf("%04x %04x %04x %04x\n", $this->x *255.0, $this->y*255.0, $this->z*255.0, $this->w*255.0 ); | |
return pack( 'CCCC', 0, $this->z*255.0, $this->y*255.0, $this->x*255.0 ); | |
} | |
public function truecolor24() { | |
// printf("%04x %04x %04x %04x\n", $this->x *255.0, $this->y*255.0, $this->z*255.0, $this->w*255.0 ); | |
return pack( 'CCC', $this->z*255.0, $this->y*255.0, $this->x*255.0 ); | |
} | |
}//vec3 | |
$colorbuffer = array(); | |
// a simple light for the scene | |
$lightdir = new vec3(-1,-1,-1); | |
$lightdir = $lightdir->normalized(); | |
for ( $py=0; $py<256; $py++ ) { | |
for ( $px=0; $px<256; $px++ ) { | |
// build a ray through the screen at the pixel to sample | |
$sp = new vec3( $px/128-1, -($py/128-1), 0 ); | |
$p = new vec3( 0, 0, 10 ); | |
$raydir = $sp->sub($p)->normalized(); | |
// march! advance along the ray until we get within | |
// "epsilon" (0.01) of the field, or until z is past | |
// a limit | |
// $steps = 0; | |
while ( $p->z > -500 ) { | |
$dist = myfield($p); | |
if ( abs($dist)<0.01 ) break; | |
$p = $p->add( $raydir->mul($dist) ); | |
//$steps++; | |
} | |
// if z is past our limit, we never hit the field | |
if ( $p->z <= -500 ) { | |
$colorbuffer[$py][$px] = new vec3(0,0,0); | |
} else { | |
// make a few samples to build a normal | |
// by numerical differentiation | |
// from http://blog.hvidtfeldts.net/index.php/2011/08/distance-estimated-3d-fractals-ii-lighting-and-coloring/ | |
$xdir = new vec3(0.0001,0,0); | |
$ydir = new vec3(0,0.0001,0); | |
$zdir = new vec3(0,0,0.0001); | |
$n = new vec3( | |
myfield($p->add($xdir))-myfield($p->sub($xdir)) | |
,myfield($p->add($ydir))-myfield($p->sub($ydir)) | |
,myfield($p->add($zdir))-myfield($p->sub($zdir)) ); | |
$n = $n->normalized(); | |
// very basic lighting | |
$color = CLAMP01(-$n->dot($lightdir)); | |
// store the pixel | |
$colorbuffer[$py][$px] = new vec3($color,$color,$color); | |
} | |
} | |
echo '.';//progress... | |
} | |
$tga = tga_createheader(256,256); | |
$tgadata = ''; | |
for ( $py=255; $py>=0; $py-- ) { | |
for ( $px=0; $px<256; $px++ ) { | |
$tgadata .= $colorbuffer[$py][$px]->truecolor24(); | |
} | |
} | |
file_put_contents('raymarched.tga',$tga.$tgadata); | |
echo "\nwrote colorbuffer to raymarched.tga\n"; | |
die; | |
function myfield( vec3 $p ) | |
{ | |
$spherepos = new vec3(0,2,-100); | |
$spherepos2 = new vec3(-2,-0,-100); | |
$planepos = new vec3(0,-10,-100); | |
$planedir = new vec3(0,1,0); | |
return min( | |
sdSphere( $p->sub($spherepos), 3.0 ) | |
,sdSphere( $p->sub($spherepos2), 5.0 ) | |
,sdPlane( $p->sub($planepos), $planedir ) | |
); | |
} | |
// some primitives, from iq's pages | |
function sdPlane( vec3 $p, vec3 $n ) | |
{ | |
return $p->dot($n); | |
} | |
function sdSphere( vec3 $p, $r ) | |
{ | |
return $p->length()-$r; | |
} | |
/* | |
* create a tga file header | |
* see http://paulbourke.net/dataformats/tga/ | |
*/ | |
function tga_createheader( $width, $height ) | |
{ | |
$a = ''; | |
$a .= pack('CC',0,0); | |
$a .= pack('C',2); // uncompressed RGB | |
$a .= pack('CC',0,0); | |
$a .= pack('CC',0,0); | |
$a .= pack('C',0); | |
$a .= pack('CC',0,0); // x origin | |
$a .= pack('CC',0,0); // y origin | |
$a .= pack('v',$width ); | |
$a .= pack('v',$height ); | |
$a .= pack('C',24); // 24 bit bitmap | |
$a .= pack('C',0); | |
return $a; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment