Skip to content

Instantly share code, notes, and snippets.

@tai2
Created March 13, 2013 13:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tai2/5151955 to your computer and use it in GitHub Desktop.
Save tai2/5151955 to your computer and use it in GitHub Desktop.
aobench php port. About 200 times slower than C implementation. c.f. https://code.google.com/p/aobench/, http://tai2.net/docs/aobench_php/
<?php
error_reporting(E_ALL);
define('WIDTH', 256);
define('HEIGHT', 256);
define('NSUBSAMPLES', 2);
define('NAO_SAMPLES', 8);
class vec
{
public $x;
public $y;
public $z;
function __construct($x = 0, $y = 0, $z = 0) {
$this->x = $x;
$this->y = $y;
$this->z = $z;
}
}
class Isect {
public $t;
public $p;
public $n;
public $hit;
function __construct($t, $p, $n, $hit) {
$this->t = $t;
$this->p = $p;
$this->n = $n;
$this->hit = $hit;
}
}
class Sphere
{
public $center;
public $radius;
function __construct($center, $radius) {
$this->center = $center;
$this->radius = $radius;
}
}
class Plane
{
public $p;
public $n;
function __construct($p, $n) {
$this->p = $p;
$this->n = $n;
}
}
class Ray
{
public $org;
public $dir;
function __construct($org, $dir) {
$this->org = $org;
$this->dir = $dir;
}
}
$spheres = array(
new Sphere(new vec(-2.0, 0.0, -3.5), 0.5),
new Sphere(new vec(-0.5, 0.0, -3.0), 0.5),
new Sphere(new vec( 1.0, 0.0, -2.2), 0.5));
$plane = new Plane(
new vec(0.0, -0.5, 0.0),
new vec(0.0, 1.0, 0.0));
function vdot($v0, $v1) {
return $v0->x * $v1->x + $v0->y * $v1->y + $v0->z * $v1->z;
}
function vcross($c, $v0, $v1) {
$c->x = $v0->y * $v1->z - $v0->z * $v1->y;
$c->y = $v0->z * $v1->x - $v0->x * $v1->z;
$c->z = $v0->x * $v1->y - $v0->y * $v1->x;
}
function vnormalize($c) {
$length = sqrt(vdot($c, $c));
if (abs($length) > 1.0e-17) {
$c->x /= $length;
$c->y /= $length;
$c->z /= $length;
}
}
function ray_sphere_intersect($isect, $ray, $sphere) {
$rs = new vec(
$ray->org->x - $sphere->center->x,
$ray->org->y - $sphere->center->y,
$ray->org->z - $sphere->center->z);
$B = vdot($rs, $ray->dir);
$C = vdot($rs, $rs) - $sphere->radius * $sphere->radius;
$D = $B * $B - $C;
if ($D > 0.0) {
$t = -$B - sqrt($D);
if (($t > 0.0) && ($t < $isect->t)) {
$isect->t = $t;
$isect->hit = true;
$isect->p->x = $ray->org->x + $ray->dir->x * $t;
$isect->p->y = $ray->org->y + $ray->dir->y * $t;
$isect->p->z = $ray->org->z + $ray->dir->z * $t;
$isect->n->x = $isect->p->x - $sphere->center->x;
$isect->n->y = $isect->p->y - $sphere->center->y;
$isect->n->z = $isect->p->z - $sphere->center->z;
vnormalize($isect->n);
}
}
}
function ray_plane_intersect($isect, $ray, $plane) {
$d = -vdot($plane->p, $plane->n);
$v = vdot($ray->dir, $plane->n);
if (abs($v) < 1.0e-17) return;
$t = -(vdot($ray->org, $plane->n) + $d) / $v;
if ($t > 0.0 && $t < $isect->t) {
$isect->t = $t;
$isect->hit = true;
$isect->p->x = $ray->org->x + $ray->dir->x * $t;
$isect->p->y = $ray->org->y + $ray->dir->y * $t;
$isect->p->z = $ray->org->z + $ray->dir->z * $t;
$isect->n = $plane->n;
}
}
function orthoBasis($basis, $n) {
$basis[2]->x = $n->x; $basis[2]->y = $n->y; $basis[2]->z = $n->z;
$basis[1]->x = 0.0; $basis[1]->y = 0.0; $basis[1]->z = 0.0;
if ($n->x < 0.6 && $n->x > -0.6) {
$basis[1]->x = 1.0;
} else if ($n->y < 0.6 && $n->y > -0.6) {
$basis[1]->y = 1.0;
} else if ($n->z < 0.6 && $n->z > -0.6) {
$basis[1]->z = 1.0;
} else {
$basis[1]->x = 1.0;
}
vcross($basis[0], $basis[1], $basis[2]);
vnormalize($basis[0]);
vcross($basis[1], $basis[2], $basis[0]);
vnormalize($basis[1]);
}
function float_rand() {
return mt_rand() / mt_getrandmax();
}
function ambient_occlusion($col, $isect)
{
global $plane, $spheres;
$ntheta = NAO_SAMPLES;
$nphi = NAO_SAMPLES;
$eps = 0.0001;
$p = new vec(
$isect->p->x + $eps * $isect->n->x,
$isect->p->y + $eps * $isect->n->y,
$isect->p->z + $eps * $isect->n->z);
$basis = array(new vec(), new vec(), new vec());
orthoBasis($basis, $isect->n);
$occlusion = 0.0;
for ($j = 0; $j < $ntheta; $j++) {
for ($i = 0; $i < $nphi; $i++) {
$theta = sqrt(float_rand());
$phi = 2.0 * M_PI * float_rand();
$x = cos($phi) * $theta;
$y = sin($phi) * $theta;
$z = sqrt(1.0 - $theta * $theta);
// local -> global
$rx = $x * $basis[0]->x + $y * $basis[1]->x + $z * $basis[2]->x;
$ry = $x * $basis[0]->y + $y * $basis[1]->y + $z * $basis[2]->y;
$rz = $x * $basis[0]->z + $y * $basis[1]->z + $z * $basis[2]->z;
$ray = new Ray($p, new vec($rx, $ry, $rz));
$occIsect = new Isect(1.0e+17, new vec(), new vec(), false);
ray_sphere_intersect($occIsect, $ray, $spheres[0]);
ray_sphere_intersect($occIsect, $ray, $spheres[1]);
ray_sphere_intersect($occIsect, $ray, $spheres[2]);
ray_plane_intersect ($occIsect, $ray, $plane);
if ($occIsect->hit) $occlusion += 1.0;
}
}
$occlusion = ($ntheta * $nphi - $occlusion) / (double)($ntheta * $nphi);
$col->x = $occlusion;
$col->y = $occlusion;
$col->z = $occlusion;
}
function clamp($f) {
$i = (int)($f * 255.25);
if ($i < 0) $i = 0;
if ($i > 255) $i = 255;
return $i;
}
function render(&$img, $w, $h, $nsubsamples)
{
global $spheres, $plane;
$fimg = array_fill(0, $w * $h * 3, 0.0);
for ($y = 0; $y < $h; $y++) {
for ($x = 0; $x < $w; $x++) {
for ($v = 0; $v < $nsubsamples; $v++) {
for ($u = 0; $u < $nsubsamples; $u++) {
$px = ($x + ($u / (double)$nsubsamples) - ($w / 2.0)) / ($w / 2.0);
$py = -($y + ($v / (double)$nsubsamples) - ($h / 2.0)) / ($h / 2.0);
$ray = new Ray(
new vec(0.0, 0.0, 0.0),
new vec($px, $py, -1.0));
vnormalize($ray->dir);
$isect = new Isect(1.0e+17, new vec(), new vec(), false);
ray_sphere_intersect($isect, $ray, $spheres[0]);
ray_sphere_intersect($isect, $ray, $spheres[1]);
ray_sphere_intersect($isect, $ray, $spheres[2]);
ray_plane_intersect($isect, $ray, $plane);
if ($isect->hit) {
$col = new vec();
ambient_occlusion($col, $isect);
$fimg[3 * ($y * $w + $x) + 0] += $col->x;
$fimg[3 * ($y * $w + $x) + 1] += $col->y;
$fimg[3 * ($y * $w + $x) + 2] += $col->z;
}
}
}
$fimg[3 * ($y * $w + $x) + 0] /= $nsubsamples * $nsubsamples;
$fimg[3 * ($y * $w + $x) + 1] /= $nsubsamples * $nsubsamples;
$fimg[3 * ($y * $w + $x) + 2] /= $nsubsamples * $nsubsamples;
$img[3 * ($y * $w + $x) + 0] = chr(clamp($fimg[3 * ($y * $w + $x) + 0]));
$img[3 * ($y * $w + $x) + 1] = chr(clamp($fimg[3 * ($y * $w + $x) + 1]));
$img[3 * ($y * $w + $x) + 2] = chr(clamp($fimg[3 * ($y * $w + $x) + 2]));
}
}
}
function saveppm($fname, $w, $h, &$img) {
$fp = fopen($fname, "wb");
assert($fp !== false);
fprintf($fp, "P6\n");
fprintf($fp, "%d %d\n", $w, $h);
fprintf($fp, "255\n");
fwrite($fp, $img);
fclose($fp);
}
function main()
{
$img = str_repeat(chr(0), WIDTH * HEIGHT * 3);
render($img, WIDTH, HEIGHT, NSUBSAMPLES);
saveppm("ao.ppm", WIDTH, HEIGHT, $img);
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment