Some stuff

This commit is contained in:
BlubbFish 2017-03-09 21:17:55 +00:00
commit c4270d4a2e
33 changed files with 4646 additions and 0 deletions

22
LICENSE.txt Normal file
View File

@ -0,0 +1,22 @@
LICENSE
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

41
Makefile Normal file
View File

@ -0,0 +1,41 @@
#
# smallptGPU & smallptCPU Makefile
#
ATISTREAMSDKROOT=/home/david/src/ati-stream-sdk-v2.0-lnx64
CC=gcc
CCFLAGS=-O3 -msse2 -mfpmath=sse -ftree-vectorize -funroll-loops -Wall \
-I$(ATISTREAMSDKROOT)/include -L$(ATISTREAMSDKROOT)/lib/x86_64 -lglut -lOpenCL
# Jens's patch for MacOS, comment the 2 lines above and un-comment the lines below
#CCFLAGS=-O3 -ftree-vectorize -msse -msse2 -msse3 -mssse3 -fvariable-expansion-in-unroller \
# -cl-fast-relaxed-math -cl-mad-enable -Wall -framework OpenCL -framework OpenGl -framework Glut
default: all
all: Makefile smallptCPU smallptGPU preprocessed_kernels
smallptCPU: smallptCPU.c displayfunc.c Makefile vec.h camera.h geom.h displayfunc.h simplernd.h scene.h geomfunc.h
$(CC) $(CCFLAGS) -DSMALLPT_CPU -o smallptCPU smallptCPU.c displayfunc.c
smallptGPU: smallptGPU.c displayfunc.c Makefile vec.h camera.h geom.h displayfunc.h simplernd.h scene.h geomfunc.h
$(CC) $(CCFLAGS) -DSMALLPT_GPU -o smallptGPU smallptGPU.c displayfunc.c
clean:
rm -rf smallptCPU smallptGPU image.ppm SmallptGPU-v1.6 smallptgpu-v1.6.tgz preprocessed_rendering_kernel.cl
preprocessed_kernels:
cpp <rendering_kernel.cl >preprocessed_rendering_kernel.cl
cpp <rendering_kernel_dl.cl >preprocessed_rendering_kernel_dl.cl
tgz: clean all
mkdir SmallptGPU-v1.6
cp -r smallptCPU smallptGPU scenes LICENSE.txt Makefile README.txt \
*.pl \
*.c \
*.h \
*.cl \
*.bat \
SmallptGPU.exe glut32.dll SmallptGPU-v1.6
tar zcvf smallptgpu-v1.6.tgz SmallptGPU-v1.6
rm -rf SmallptGPU-v1.6

58
README.txt Normal file
View File

@ -0,0 +1,58 @@
SmallptCPU vs. SmallptGPU
=========================
SmallptGPU is a small and simple demo written in OpenCL in order to test the
performance of this new standard. It is based on Kevin Beason's Smallpt available
at http://www.kevinbeason.com/smallpt/
SmallptGPU has been written using the ATI OpenCL SDK 2.0 on Linux but it
should work on any platform/implementation.
glut32.dll has been downloaded from Nate Robins's http://www.xmission.com/~nate/glut.html
How to compile
==============
Just edit the Makefile and use an appropriate value for ATISTREAMSDKROOT.
Key bindings
============
'p' - save image.ppm
ESC - exit
Arrow keys - rotate camera left/right/up/down
'a' and 'd' - move camera left and right
'w' and 's' - move camera forward and backward
'r' and 'f' - move camera up and down
PageUp and PageDown - move camera target up and down
' ' - refresh the window
'+' and '-' - to select next/previous object
'2', '3', '4', '5', '6', '8', '9' - to move selected object
History
=======
V1.6 - Thanks to Jens and all the discussion at http://www.luxrender.net/forum/viewtopic.php?f=21&t=2947&start=240#p29397
now SmallptGPU works fine with MacOS and NVIDIA cards. A bug in the Apple's OpenCL
compiler has been found (http://www.khronos.org/message_boards/viewtopic.php?f=37&t=2148)
and a workaround has been applied to SmallptGPU. Added a new kernel with
direct lighting surface integrator (very fast indeed).
V1.5 - Thanks to discussion at http://forum.beyond3d.com/showthread.php?t=55913
the perfomances on NVIDA GPUs have been improved. They are not yet where they should
be but are lot better now.
V1.4 - Updated for ATI SDK 2.0, fixed a problem in object selection
V1.3 - Jens's patch for MacOS, added on-screen help, fixed performance
estimation, removed movie recording, added on-screen help, added Windows binaries
V1.2 - Indirect diffuse path can be now disabled/enabled (available only
on CPU version because a bug of ATI's compiler), optimized buffers
reallocation, added keys to select/move objects
V1.1 - Fixed few portability problems, added support to save movie, fixed a
problem in window resize code
V1.0 - First release

View File

@ -0,0 +1 @@
smallptGPU.exe 1 128 rendering_kernel.cl 640 480 scenes\cornell.scn

View File

@ -0,0 +1 @@
smallptGPU.exe 1 32 rendering_kernel.cl 640 480 scenes\cornell.scn

View File

@ -0,0 +1 @@
smallptGPU.exe 1 64 rendering_kernel.cl 640 480 scenes\cornell.scn

View File

@ -0,0 +1 @@
smallptGPU.exe 1 64 rendering_kernel_dl.cl 640 480 scenes\cornell.scn

View File

@ -0,0 +1 @@
smallptGPU.exe 1 64 rendering_kernel.cl 640 480 scenes\simple.scn

BIN
SmallptGPU.exe Normal file

Binary file not shown.

37
camera.h Normal file
View File

@ -0,0 +1,37 @@
/*
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _CAMERA_H
#define _CAMERA_H
#include "vec.h"
typedef struct {
/* User defined values */
Vec orig, target;
/* Calculated values */
Vec dir, x, y;
} Camera;
#endif /* _CAMERA_H */

431
displayfunc.c Normal file
View File

@ -0,0 +1,431 @@
/*
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#define _USE_MATH_DEFINES
#endif
#include <math.h>
#if defined(__linux__) || defined(__APPLE__)
#include <sys/time.h>
#elif defined (WIN32)
#include <windows.h>
#else
Unsupported Platform !!!
#endif
#include "camera.h"
#include "geom.h"
#include "displayfunc.h"
extern void ReInit(const int);
extern void ReInitScene();
extern void UpdateRendering();
extern void UpdateCamera();
extern Camera camera;
extern Sphere *spheres;
extern unsigned int sphereCount;
int amiSmallptCPU;
int width = 640;
int height = 480;
unsigned int *pixels;
char captionBuffer[256];
static int printHelp = 1;
static int currentSphere;
double WallClockTime() {
#if defined(__linux__) || defined(__APPLE__)
struct timeval t;
gettimeofday(&t, NULL);
return t.tv_sec + t.tv_usec / 1000000.0;
#elif defined (WIN32)
return GetTickCount() / 1000.0;
#else
Unsupported Platform !!!
#endif
}
static void PrintString(void *font, const char *string) {
int len, i;
len = (int)strlen(string);
for (i = 0; i < len; i++)
glutBitmapCharacter(font, string[i]);
}
static void PrintHelp() {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(0.f, 0.f, 0.5f, 0.5f);
glRecti(40, 40, 600, 440);
glColor3f(1.f, 1.f, 1.f);
glRasterPos2i(300, 420);
PrintString(GLUT_BITMAP_HELVETICA_18, "Help");
glRasterPos2i(60, 390);
PrintString(GLUT_BITMAP_HELVETICA_18, "h - toggle Help");
glRasterPos2i(60, 360);
PrintString(GLUT_BITMAP_HELVETICA_18, "arrow Keys - rotate camera left/right/up/down");
glRasterPos2i(60, 330);
PrintString(GLUT_BITMAP_HELVETICA_18, "a and d - move camera left and right");
glRasterPos2i(60, 300);
PrintString(GLUT_BITMAP_HELVETICA_18, "w and s - move camera forward and backward");
glRasterPos2i(60, 270);
PrintString(GLUT_BITMAP_HELVETICA_18, "r and f - move camera up and down");
glRasterPos2i(60, 240);
PrintString(GLUT_BITMAP_HELVETICA_18, "PageUp and PageDown - move camera target up and down");
glRasterPos2i(60, 210);
PrintString(GLUT_BITMAP_HELVETICA_18, "+ and - - to select next/previous object");
glRasterPos2i(60, 180);
PrintString(GLUT_BITMAP_HELVETICA_18, "2, 3, 4, 5, 6, 8, 9 - to move selected object");
glDisable(GL_BLEND);
}
void ReadScene(char *fileName) {
fprintf(stderr, "Reading scene: %s\n", fileName);
FILE *f = fopen(fileName, "r");
if (!f) {
fprintf(stderr, "Failed to open file: %s\n", fileName);
exit(-1);
}
/* Read the camera position */
int c = fscanf(f,"camera %f %f %f %f %f %f\n",
&camera.orig.x, &camera.orig.y, &camera.orig.z,
&camera.target.x, &camera.target.y, &camera.target.z);
if (c != 6) {
fprintf(stderr, "Failed to read 6 camera parameters: %d\n", c);
exit(-1);
}
/* Read the sphere count */
c = fscanf(f,"size %u\n", &sphereCount);
if (c != 1) {
fprintf(stderr, "Failed to read sphere count: %d\n", c);
exit(-1);
}
fprintf(stderr, "Scene size: %d\n", sphereCount);
/* Read all spheres */
spheres = (Sphere *)malloc(sizeof(Sphere) * sphereCount);
unsigned int i;
for (i = 0; i < sphereCount; i++) {
Sphere *s = &spheres[i];
int mat;
int c = fscanf(f,"sphere %f %f %f %f %f %f %f %f %f %f %d\n",
&s->rad,
&s->p.x, &s->p.y, &s->p.z,
&s->e.x, &s->e.y, &s->e.z,
&s->c.x, &s->c.y, &s->c.z,
&mat);
switch (mat) {
case 0:
s->refl = DIFF;
break;
case 1:
s->refl = SPEC;
break;
case 2:
s->refl = REFR;
break;
default:
fprintf(stderr, "Failed to read material type for sphere #%d: %d\n", i, mat);
exit(-1);
break;
}
if (c != 11) {
fprintf(stderr, "Failed to read sphere #%d: %d\n", i, c);
exit(-1);
}
}
fclose(f);
}
void UpdateCamera() {
vsub(camera.dir, camera.target, camera.orig);
vnorm(camera.dir);
const Vec up = {0.f, 1.f, 0.f};
const float fov = (M_PI / 180.f) * 45.f;
vxcross(camera.x, camera.dir, up);
vnorm(camera.x);
vsmul(camera.x, width * fov / height, camera.x);
vxcross(camera.y, camera.x, camera.dir);
vnorm(camera.y);
vsmul(camera.y, fov, camera.y);
}
void idleFunc(void) {
UpdateRendering();
glutPostRedisplay();
}
void displayFunc(void) {
glClear(GL_COLOR_BUFFER_BIT);
glRasterPos2i(0, 0);
glDrawPixels(width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// Title
glColor3f(1.f, 1.f, 1.f);
glRasterPos2i(4, height - 16);
if (amiSmallptCPU)
PrintString(GLUT_BITMAP_HELVETICA_18, "SmallptCPU v1.6 (Written by David Bucciarelli)");
else
PrintString(GLUT_BITMAP_HELVETICA_18, "SmallptGPU v1.6 (Written by David Bucciarelli)");
// Caption line 0
glColor3f(1.f, 1.f, 1.f);
glRasterPos2i(4, 10);
PrintString(GLUT_BITMAP_HELVETICA_18, captionBuffer);
if (printHelp) {
glPushMatrix();
glLoadIdentity();
glOrtho(-0.5, 639.5, -0.5, 479.5, -1.0, 1.0);
PrintHelp();
glPopMatrix();
}
glutSwapBuffers();
}
void reshapeFunc(int newWidth, int newHeight) {
width = newWidth;
height = newHeight;
glViewport(0, 0, width, height);
glLoadIdentity();
glOrtho(0.f, width - 1.f, 0.f, height - 1.f, -1.f, 1.f);
ReInit(1);
glutPostRedisplay();
}
#define MOVE_STEP 10.0f
#define ROTATE_STEP (2.f * M_PI / 180.f)
void keyFunc(unsigned char key, int x, int y) {
switch (key) {
case 'p': {
FILE *f = fopen("image.ppm", "w"); // Write image to PPM file.
if (!f) {
fprintf(stderr, "Failed to open image file: image.ppm\n");
} else {
fprintf(f, "P3\n%d %d\n%d\n", width, height, 255);
int x, y;
for (y = height - 1; y >= 0; --y) {
unsigned char *p = (unsigned char *)(&pixels[y * width]);
for (x = 0; x < width; ++x, p += 4)
fprintf(f, "%d %d %d ", p[0], p[1], p[2]);
}
fclose(f);
}
break;
}
case 27: /* Escape key */
fprintf(stderr, "Done.\n");
exit(0);
break;
case ' ': /* Refresh display */
ReInit(1);
break;
case 'a': {
Vec dir = camera.x;
vnorm(dir);
vsmul(dir, -MOVE_STEP, dir);
vadd(camera.orig, camera.orig, dir);
vadd(camera.target, camera.target, dir);
ReInit(0);
break;
}
case 'd': {
Vec dir = camera.x;
vnorm(dir);
vsmul(dir, MOVE_STEP, dir);
vadd(camera.orig, camera.orig, dir);
vadd(camera.target, camera.target, dir);
ReInit(0);
break;
}
case 'w': {
Vec dir = camera.dir;
vsmul(dir, MOVE_STEP, dir);
vadd(camera.orig, camera.orig, dir);
vadd(camera.target, camera.target, dir);
ReInit(0);
break;
}
case 's': {
Vec dir = camera.dir;
vsmul(dir, -MOVE_STEP, dir);
vadd(camera.orig, camera.orig, dir);
vadd(camera.target, camera.target, dir);
ReInit(0);
break;
}
case 'r':
camera.orig.y += MOVE_STEP;
camera.target.y += MOVE_STEP;
ReInit(0);
break;
case 'f':
camera.orig.y -= MOVE_STEP;
camera.target.y -= MOVE_STEP;
ReInit(0);
break;
case '+':
currentSphere = (currentSphere + 1) % sphereCount;
fprintf(stderr, "Selected sphere %d (%f %f %f)\n", currentSphere,
spheres[currentSphere].p.x, spheres[currentSphere].p.y, spheres[currentSphere].p.z);
ReInitScene();
break;
case '-':
currentSphere = (currentSphere + (sphereCount - 1)) % sphereCount;
fprintf(stderr, "Selected sphere %d (%f %f %f)\n", currentSphere,
spheres[currentSphere].p.x, spheres[currentSphere].p.y, spheres[currentSphere].p.z);
ReInitScene();
break;
case '4':
spheres[currentSphere].p.x -= 0.5f * MOVE_STEP;
ReInitScene();
break;
case '6':
spheres[currentSphere].p.x += 0.5f * MOVE_STEP;
ReInitScene();
break;
case '8':
spheres[currentSphere].p.z -= 0.5f * MOVE_STEP;
ReInitScene();
break;
case '2':
spheres[currentSphere].p.z += 0.5f * MOVE_STEP;
ReInitScene();
break;
case '9':
spheres[currentSphere].p.y += 0.5f * MOVE_STEP;
ReInitScene();
break;
case '3':
spheres[currentSphere].p.y -= 0.5f * MOVE_STEP;
ReInitScene();
break;
case 'h':
printHelp = (!printHelp);
break;
default:
break;
}
}
void specialFunc(int key, int x, int y) {
switch (key) {
case GLUT_KEY_UP: {
Vec t = camera.target;
vsub(t, t, camera.orig);
t.y = t.y * cos(-ROTATE_STEP) + t.z * sin(-ROTATE_STEP);
t.z = -t.y * sin(-ROTATE_STEP) + t.z * cos(-ROTATE_STEP);
vadd(t, t, camera.orig);
camera.target = t;
ReInit(0);
break;
}
case GLUT_KEY_DOWN: {
Vec t = camera.target;
vsub(t, t, camera.orig);
t.y = t.y * cos(ROTATE_STEP) + t.z * sin(ROTATE_STEP);
t.z = -t.y * sin(ROTATE_STEP) + t.z * cos(ROTATE_STEP);
vadd(t, t, camera.orig);
camera.target = t;
ReInit(0);
break;
}
case GLUT_KEY_LEFT: {
Vec t = camera.target;
vsub(t, t, camera.orig);
t.x = t.x * cos(-ROTATE_STEP) - t.z * sin(-ROTATE_STEP);
t.z = t.x * sin(-ROTATE_STEP) + t.z * cos(-ROTATE_STEP);
vadd(t, t, camera.orig);
camera.target = t;
ReInit(0);
break;
}
case GLUT_KEY_RIGHT: {
Vec t = camera.target;
vsub(t, t, camera.orig);
t.x = t.x * cos(ROTATE_STEP) - t.z * sin(ROTATE_STEP);
t.z = t.x * sin(ROTATE_STEP) + t.z * cos(ROTATE_STEP);
vadd(t, t, camera.orig);
camera.target = t;
ReInit(0);
break;
}
case GLUT_KEY_PAGE_UP:
camera.target.y += MOVE_STEP;
ReInit(0);
break;
case GLUT_KEY_PAGE_DOWN:
camera.target.y -= MOVE_STEP;
ReInit(0);
break;
default:
break;
}
}
void InitGlut(int argc, char *argv[], char *windowTittle) {
glutInitWindowSize(width, height);
glutInitWindowPosition(0,0);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
glutInit(&argc, argv);
glutCreateWindow(windowTittle);
glutReshapeFunc(reshapeFunc);
glutKeyboardFunc(keyFunc);
glutSpecialFunc(specialFunc);
glutDisplayFunc(displayFunc);
glutIdleFunc(idleFunc);
glViewport(0, 0, width, height);
glLoadIdentity();
glOrtho(0.f, width - 1.f, 0.f, height - 1.f, -1.f, 1.f);
}

53
displayfunc.h Normal file
View File

@ -0,0 +1,53 @@
/*
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _DISPLAYFUNC_H
#define _DISPLAYFUNC_H
#include <math.h>
// Jens's patch for MacOS
#ifdef __APPLE__
#include <GLut/glut.h>
#else
#include <GL/glut.h>
#endif
#include "vec.h"
extern int width;
extern int height;
extern unsigned int *pixels;
extern unsigned int renderingFlags;
extern char captionBuffer[256];
extern int amiSmallptCPU;
extern void InitGlut(int argc, char *argv[], char *windowTittle);
extern double WallClockTime();
extern void ReadScene(char *);
extern void UpdateCamera();
#endif /* _DISPLAYFUNC_H */

50
geom.h Normal file
View File

@ -0,0 +1,50 @@
/*
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _GEOM_H
#define _GEOM_H
#include "vec.h"
#define EPSILON 0.01f
#define FLOAT_PI 3.14159265358979323846f
typedef struct {
Vec o, d;
} Ray;
#define rinit(r, a, b) { vassign((r).o, a); vassign((r).d, b); }
#define rassign(a, b) { vassign((a).o, (b).o); vassign((a).d, (b).d); }
enum Refl {
DIFF, SPEC, REFR
}; /* material types, used in radiance() */
typedef struct {
float rad; /* radius */
Vec p, e, c; /* position, emission, color */
enum Refl refl; /* reflection type (DIFFuse, SPECular, REFRactive) */
} Sphere;
#endif /* _GEOM_H */

488
geomfunc.h Normal file
View File

@ -0,0 +1,488 @@
/*
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _GEOMFUNC_H
#define _GEOMFUNC_H
#include "geom.h"
#include "simplernd.h"
#ifndef SMALLPT_GPU
static float SphereIntersect(
#ifdef GPU_KERNEL
OCL_CONSTANT_BUFFER
#endif
const Sphere *s,
const Ray *r) { /* returns distance, 0 if nohit */
Vec op; /* Solve t^2*d.d + 2*t*(o-p).d + (o-p).(o-p)-R^2 = 0 */
vsub(op, s->p, r->o);
float b = vdot(op, r->d);
float det = b * b - vdot(op, op) + s->rad * s->rad;
if (det < 0.f)
return 0.f;
else
det = sqrt(det);
float t = b - det;
if (t > EPSILON)
return t;
else {
t = b + det;
if (t > EPSILON)
return t;
else
return 0.f;
}
}
static void UniformSampleSphere(const float u1, const float u2, Vec *v) {
const float zz = 1.f - 2.f * u1;
const float r = sqrt(max(0.f, 1.f - zz * zz));
const float phi = 2.f * FLOAT_PI * u2;
const float xx = r * cos(phi);
const float yy = r * sin(phi);
vinit(*v, xx, yy, zz);
}
static int Intersect(
#ifdef GPU_KERNEL
OCL_CONSTANT_BUFFER
#endif
const Sphere *spheres,
const unsigned int sphereCount,
const Ray *r,
float *t,
unsigned int *id) {
float inf = (*t) = 1e20f;
unsigned int i = sphereCount;
for (; i--;) {
const float d = SphereIntersect(&spheres[i], r);
if ((d != 0.f) && (d < *t)) {
*t = d;
*id = i;
}
}
return (*t < inf);
}
static int IntersectP(
#ifdef GPU_KERNEL
OCL_CONSTANT_BUFFER
#endif
const Sphere *spheres,
const unsigned int sphereCount,
const Ray *r,
const float maxt) {
unsigned int i = sphereCount;
for (; i--;) {
const float d = SphereIntersect(&spheres[i], r);
if ((d != 0.f) && (d < maxt))
return 1;
}
return 0;
}
static void SampleLights(
#ifdef GPU_KERNEL
OCL_CONSTANT_BUFFER
#endif
const Sphere *spheres,
const unsigned int sphereCount,
unsigned int *seed0, unsigned int *seed1,
const Vec *hitPoint,
const Vec *normal,
Vec *result) {
vclr(*result);
/* For each light */
unsigned int i;
for (i = 0; i < sphereCount; i++) {
#ifdef GPU_KERNEL
OCL_CONSTANT_BUFFER
#endif
const Sphere *light = &spheres[i];
if (!viszero(light->e)) {
/* It is a light source */
Ray shadowRay;
shadowRay.o = *hitPoint;
/* Choose a point over the light source */
Vec unitSpherePoint;
UniformSampleSphere(GetRandom(seed0, seed1), GetRandom(seed0, seed1), &unitSpherePoint);
Vec spherePoint;
vsmul(spherePoint, light->rad, unitSpherePoint);
vadd(spherePoint, spherePoint, light->p);
/* Build the shadow ray direction */
vsub(shadowRay.d, spherePoint, *hitPoint);
const float len = sqrt(vdot(shadowRay.d, shadowRay.d));
vsmul(shadowRay.d, 1.f / len, shadowRay.d);
float wo = vdot(shadowRay.d, unitSpherePoint);
if (wo > 0.f) {
/* It is on the other half of the sphere */
continue;
} else
wo = -wo;
/* Check if the light is visible */
const float wi = vdot(shadowRay.d, *normal);
if ((wi > 0.f) && (!IntersectP(spheres, sphereCount, &shadowRay, len - EPSILON))) {
Vec c; vassign(c, light->e);
const float s = (4.f * FLOAT_PI * light->rad * light->rad) * wi * wo / (len *len);
vsmul(c, s, c);
vadd(*result, *result, c);
}
}
}
}
static void RadiancePathTracing(
#ifdef GPU_KERNEL
OCL_CONSTANT_BUFFER
#endif
const Sphere *spheres,
const unsigned int sphereCount,
const Ray *startRay,
unsigned int *seed0, unsigned int *seed1,
Vec *result) {
Ray currentRay; rassign(currentRay, *startRay);
Vec rad; vinit(rad, 0.f, 0.f, 0.f);
Vec throughput; vinit(throughput, 1.f, 1.f, 1.f);
unsigned int depth = 0;
int specularBounce = 1;
for (;; ++depth) {
// Removed Russian Roulette in order to improve execution on SIMT
if (depth > 6) {
*result = rad;
return;
}
float t; /* distance to intersection */
unsigned int id = 0; /* id of intersected object */
if (!Intersect(spheres, sphereCount, &currentRay, &t, &id)) {
*result = rad; /* if miss, return */
return;
}
#ifdef GPU_KERNEL
OCL_CONSTANT_BUFFER
#endif
const Sphere *obj = &spheres[id]; /* the hit object */
Vec hitPoint;
vsmul(hitPoint, t, currentRay.d);
vadd(hitPoint, currentRay.o, hitPoint);
Vec normal;
vsub(normal, hitPoint, obj->p);
vnorm(normal);
const float dp = vdot(normal, currentRay.d);
Vec nl;
// SIMT optimization
const float invSignDP = -1.f * sign(dp);
vsmul(nl, invSignDP, normal);
/* Add emitted light */
Vec eCol; vassign(eCol, obj->e);
if (!viszero(eCol)) {
if (specularBounce) {
vsmul(eCol, fabs(dp), eCol);
vmul(eCol, throughput, eCol);
vadd(rad, rad, eCol);
}
*result = rad;
return;
}
if (obj->refl == DIFF) { /* Ideal DIFFUSE reflection */
specularBounce = 0;
vmul(throughput, throughput, obj->c);
/* Direct lighting component */
Vec Ld;
SampleLights(spheres, sphereCount, seed0, seed1, &hitPoint, &nl, &Ld);
vmul(Ld, throughput, Ld);
vadd(rad, rad, Ld);
/* Diffuse component */
float r1 = 2.f * FLOAT_PI * GetRandom(seed0, seed1);
float r2 = GetRandom(seed0, seed1);
float r2s = sqrt(r2);
Vec w; vassign(w, nl);
Vec u, a;
if (fabs(w.x) > .1f) {
vinit(a, 0.f, 1.f, 0.f);
} else {
vinit(a, 1.f, 0.f, 0.f);
}
vxcross(u, a, w);
vnorm(u);
Vec v;
vxcross(v, w, u);
Vec newDir;
vsmul(u, cos(r1) * r2s, u);
vsmul(v, sin(r1) * r2s, v);
vadd(newDir, u, v);
vsmul(w, sqrt(1 - r2), w);
vadd(newDir, newDir, w);
currentRay.o = hitPoint;
currentRay.d = newDir;
continue;
} else if (obj->refl == SPEC) { /* Ideal SPECULAR reflection */
specularBounce = 1;
Vec newDir;
vsmul(newDir, 2.f * vdot(normal, currentRay.d), normal);
vsub(newDir, currentRay.d, newDir);
vmul(throughput, throughput, obj->c);
rinit(currentRay, hitPoint, newDir);
continue;
} else {
specularBounce = 1;
Vec newDir;
vsmul(newDir, 2.f * vdot(normal, currentRay.d), normal);
vsub(newDir, currentRay.d, newDir);
Ray reflRay; rinit(reflRay, hitPoint, newDir); /* Ideal dielectric REFRACTION */
int into = (vdot(normal, nl) > 0); /* Ray from outside going in? */
float nc = 1.f;
float nt = 1.5f;
float nnt = into ? nc / nt : nt / nc;
float ddn = vdot(currentRay.d, nl);
float cos2t = 1.f - nnt * nnt * (1.f - ddn * ddn);
if (cos2t < 0.f) { /* Total internal reflection */
vmul(throughput, throughput, obj->c);
rassign(currentRay, reflRay);
continue;
}
float kk = (into ? 1 : -1) * (ddn * nnt + sqrt(cos2t));
Vec nkk;
vsmul(nkk, kk, normal);
Vec transDir;
vsmul(transDir, nnt, currentRay.d);
vsub(transDir, transDir, nkk);
vnorm(transDir);
float a = nt - nc;
float b = nt + nc;
float R0 = a * a / (b * b);
float c = 1 - (into ? -ddn : vdot(transDir, normal));
float Re = R0 + (1 - R0) * c * c * c * c*c;
float Tr = 1.f - Re;
float P = .25f + .5f * Re;
float RP = Re / P;
float TP = Tr / (1.f - P);
if (GetRandom(seed0, seed1) < P) { /* R.R. */
vsmul(throughput, RP, throughput);
vmul(throughput, throughput, obj->c);
rassign(currentRay, reflRay);
continue;
} else {
vsmul(throughput, TP, throughput);
vmul(throughput, throughput, obj->c);
rinit(currentRay, hitPoint, transDir);
continue;
}
}
}
}
static void RadianceDirectLighting(
#ifdef GPU_KERNEL
OCL_CONSTANT_BUFFER
#endif
const Sphere *spheres,
const unsigned int sphereCount,
const Ray *startRay,
unsigned int *seed0, unsigned int *seed1,
Vec *result) {
Ray currentRay; rassign(currentRay, *startRay);
Vec rad; vinit(rad, 0.f, 0.f, 0.f);
Vec throughput; vinit(throughput, 1.f, 1.f, 1.f);
unsigned int depth = 0;
int specularBounce = 1;
for (;; ++depth) {
// Removed Russian Roulette in order to improve execution on SIMT
if (depth > 6) {
*result = rad;
return;
}
float t; /* distance to intersection */
unsigned int id = 0; /* id of intersected object */
if (!Intersect(spheres, sphereCount, &currentRay, &t, &id)) {
*result = rad; /* if miss, return */
return;
}
#ifdef GPU_KERNEL
OCL_CONSTANT_BUFFER
#endif
const Sphere *obj = &spheres[id]; /* the hit object */
Vec hitPoint;
vsmul(hitPoint, t, currentRay.d);
vadd(hitPoint, currentRay.o, hitPoint);
Vec normal;
vsub(normal, hitPoint, obj->p);
vnorm(normal);
const float dp = vdot(normal, currentRay.d);
Vec nl;
// SIMT optimization
const float invSignDP = -1.f * sign(dp);
vsmul(nl, invSignDP, normal);
/* Add emitted light */
Vec eCol; vassign(eCol, obj->e);
if (!viszero(eCol)) {
if (specularBounce) {
vsmul(eCol, fabs(dp), eCol);
vmul(eCol, throughput, eCol);
vadd(rad, rad, eCol);
}
*result = rad;
return;
}
if (obj->refl == DIFF) { /* Ideal DIFFUSE reflection */
specularBounce = 0;
vmul(throughput, throughput, obj->c);
/* Direct lighting component */
Vec Ld;
SampleLights(spheres, sphereCount, seed0, seed1, &hitPoint, &nl, &Ld);
vmul(Ld, throughput, Ld);
vadd(rad, rad, Ld);
*result = rad;
return;
} else if (obj->refl == SPEC) { /* Ideal SPECULAR reflection */
specularBounce = 1;
Vec newDir;
vsmul(newDir, 2.f * vdot(normal, currentRay.d), normal);
vsub(newDir, currentRay.d, newDir);
vmul(throughput, throughput, obj->c);
rinit(currentRay, hitPoint, newDir);
continue;
} else {
specularBounce = 1;
Vec newDir;
vsmul(newDir, 2.f * vdot(normal, currentRay.d), normal);
vsub(newDir, currentRay.d, newDir);
Ray reflRay; rinit(reflRay, hitPoint, newDir); /* Ideal dielectric REFRACTION */
int into = (vdot(normal, nl) > 0); /* Ray from outside going in? */
float nc = 1.f;
float nt = 1.5f;
float nnt = into ? nc / nt : nt / nc;
float ddn = vdot(currentRay.d, nl);
float cos2t = 1.f - nnt * nnt * (1.f - ddn * ddn);
if (cos2t < 0.f) { /* Total internal reflection */
vmul(throughput, throughput, obj->c);
rassign(currentRay, reflRay);
continue;
}
float kk = (into ? 1 : -1) * (ddn * nnt + sqrt(cos2t));
Vec nkk;
vsmul(nkk, kk, normal);
Vec transDir;
vsmul(transDir, nnt, currentRay.d);
vsub(transDir, transDir, nkk);
vnorm(transDir);
float a = nt - nc;
float b = nt + nc;
float R0 = a * a / (b * b);
float c = 1 - (into ? -ddn : vdot(transDir, normal));
float Re = R0 + (1 - R0) * c * c * c * c*c;
float Tr = 1.f - Re;
float P = .25f + .5f * Re;
float RP = Re / P;
float TP = Tr / (1.f - P);
if (GetRandom(seed0, seed1) < P) { /* R.R. */
vsmul(throughput, RP, throughput);
vmul(throughput, throughput, obj->c);
rassign(currentRay, reflRay);
continue;
} else {
vsmul(throughput, TP, throughput);
vmul(throughput, throughput, obj->c);
rinit(currentRay, hitPoint, transDir);
continue;
}
}
}
}
#endif
#endif /* _GEOMFUNC_H */

BIN
glut32.dll Normal file

Binary file not shown.

View File

@ -0,0 +1,586 @@
# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "<stdin>"
# 26 "<stdin>"
# 1 "camera.h" 1
# 27 "camera.h"
# 1 "vec.h" 1
# 27 "vec.h"
typedef struct {
float x, y, z;
} Vec;
# 28 "camera.h" 2
typedef struct {
Vec orig, target;
Vec dir, x, y;
} Camera;
# 27 "<stdin>" 2
# 1 "geomfunc.h" 1
# 27 "geomfunc.h"
# 1 "geom.h" 1
# 32 "geom.h"
typedef struct {
Vec o, d;
} Ray;
enum Refl {
DIFF, SPEC, REFR
};
typedef struct {
float rad;
Vec p, e, c;
enum Refl refl;
} Sphere;
# 28 "geomfunc.h" 2
# 1 "simplernd.h" 1
# 34 "simplernd.h"
static float GetRandom(unsigned int *seed0, unsigned int *seed1) {
*seed0 = 36969 * ((*seed0) & 65535) + ((*seed0) >> 16);
*seed1 = 18000 * ((*seed1) & 65535) + ((*seed1) >> 16);
unsigned int ires = ((*seed0) << 16) + (*seed1);
union {
float f;
unsigned int ui;
} res;
res.ui = (ires & 0x007fffff) | 0x40000000;
return (res.f - 2.f) / 2.f;
}
# 29 "geomfunc.h" 2
static float SphereIntersect(
__constant
const Sphere *s,
const Ray *r) {
Vec op;
{ (op).x = (s->p).x - (r->o).x; (op).y = (s->p).y - (r->o).y; (op).z = (s->p).z - (r->o).z; };
float b = ((op).x * (r->d).x + (op).y * (r->d).y + (op).z * (r->d).z);
float det = b * b - ((op).x * (op).x + (op).y * (op).y + (op).z * (op).z) + s->rad * s->rad;
if (det < 0.f)
return 0.f;
else
det = sqrt(det);
float t = b - det;
if (t > 0.01f)
return t;
else {
t = b + det;
if (t > 0.01f)
return t;
else
return 0.f;
}
}
static void UniformSampleSphere(const float u1, const float u2, Vec *v) {
const float zz = 1.f - 2.f * u1;
const float r = sqrt(max(0.f, 1.f - zz * zz));
const float phi = 2.f * 3.14159265358979323846f * u2;
const float xx = r * cos(phi);
const float yy = r * sin(phi);
{ (*v).x = xx; (*v).y = yy; (*v).z = zz; };
}
static int Intersect(
__constant
const Sphere *spheres,
const unsigned int sphereCount,
const Ray *r,
float *t,
unsigned int *id) {
float inf = (*t) = 1e20f;
unsigned int i = sphereCount;
for (; i--;) {
const float d = SphereIntersect(&spheres[i], r);
if ((d != 0.f) && (d < *t)) {
*t = d;
*id = i;
}
}
return (*t < inf);
}
static int IntersectP(
__constant
const Sphere *spheres,
const unsigned int sphereCount,
const Ray *r,
const float maxt) {
unsigned int i = sphereCount;
for (; i--;) {
const float d = SphereIntersect(&spheres[i], r);
if ((d != 0.f) && (d < maxt))
return 1;
}
return 0;
}
static void SampleLights(
__constant
const Sphere *spheres,
const unsigned int sphereCount,
unsigned int *seed0, unsigned int *seed1,
const Vec *hitPoint,
const Vec *normal,
Vec *result) {
{ (*result).x = 0.f; (*result).y = 0.f; (*result).z = 0.f; };
unsigned int i;
for (i = 0; i < sphereCount; i++) {
__constant
const Sphere *light = &spheres[i];
if (!(((light->e).x == 0.f) && ((light->e).x == 0.f) && ((light->e).z == 0.f))) {
Ray shadowRay;
shadowRay.o = *hitPoint;
Vec unitSpherePoint;
UniformSampleSphere(GetRandom(seed0, seed1), GetRandom(seed0, seed1), &unitSpherePoint);
Vec spherePoint;
{ float k = (light->rad); { (spherePoint).x = k * (unitSpherePoint).x; (spherePoint).y = k * (unitSpherePoint).y; (spherePoint).z = k * (unitSpherePoint).z; } };
{ (spherePoint).x = (spherePoint).x + (light->p).x; (spherePoint).y = (spherePoint).y + (light->p).y; (spherePoint).z = (spherePoint).z + (light->p).z; };
{ (shadowRay.d).x = (spherePoint).x - (*hitPoint).x; (shadowRay.d).y = (spherePoint).y - (*hitPoint).y; (shadowRay.d).z = (spherePoint).z - (*hitPoint).z; };
const float len = sqrt(((shadowRay.d).x * (shadowRay.d).x + (shadowRay.d).y * (shadowRay.d).y + (shadowRay.d).z * (shadowRay.d).z));
{ float k = (1.f / len); { (shadowRay.d).x = k * (shadowRay.d).x; (shadowRay.d).y = k * (shadowRay.d).y; (shadowRay.d).z = k * (shadowRay.d).z; } };
float wo = ((shadowRay.d).x * (unitSpherePoint).x + (shadowRay.d).y * (unitSpherePoint).y + (shadowRay.d).z * (unitSpherePoint).z);
if (wo > 0.f) {
continue;
} else
wo = -wo;
const float wi = ((shadowRay.d).x * (*normal).x + (shadowRay.d).y * (*normal).y + (shadowRay.d).z * (*normal).z);
if ((wi > 0.f) && (!IntersectP(spheres, sphereCount, &shadowRay, len - 0.01f))) {
Vec c; { (c).x = (light->e).x; (c).y = (light->e).y; (c).z = (light->e).z; };
const float s = (4.f * 3.14159265358979323846f * light->rad * light->rad) * wi * wo / (len *len);
{ float k = (s); { (c).x = k * (c).x; (c).y = k * (c).y; (c).z = k * (c).z; } };
{ (*result).x = (*result).x + (c).x; (*result).y = (*result).y + (c).y; (*result).z = (*result).z + (c).z; };
}
}
}
}
static void RadiancePathTracing(
__constant
const Sphere *spheres,
const unsigned int sphereCount,
const Ray *startRay,
unsigned int *seed0, unsigned int *seed1,
Vec *result) {
Ray currentRay; { { ((currentRay).o).x = ((*startRay).o).x; ((currentRay).o).y = ((*startRay).o).y; ((currentRay).o).z = ((*startRay).o).z; }; { ((currentRay).d).x = ((*startRay).d).x; ((currentRay).d).y = ((*startRay).d).y; ((currentRay).d).z = ((*startRay).d).z; }; };
Vec rad; { (rad).x = 0.f; (rad).y = 0.f; (rad).z = 0.f; };
Vec throughput; { (throughput).x = 1.f; (throughput).y = 1.f; (throughput).z = 1.f; };
unsigned int depth = 0;
int specularBounce = 1;
for (;; ++depth) {
if (depth > 6) {
*result = rad;
return;
}
float t;
unsigned int id = 0;
if (!Intersect(spheres, sphereCount, &currentRay, &t, &id)) {
*result = rad;
return;
}
__constant
const Sphere *obj = &spheres[id];
Vec hitPoint;
{ float k = (t); { (hitPoint).x = k * (currentRay.d).x; (hitPoint).y = k * (currentRay.d).y; (hitPoint).z = k * (currentRay.d).z; } };
{ (hitPoint).x = (currentRay.o).x + (hitPoint).x; (hitPoint).y = (currentRay.o).y + (hitPoint).y; (hitPoint).z = (currentRay.o).z + (hitPoint).z; };
Vec normal;
{ (normal).x = (hitPoint).x - (obj->p).x; (normal).y = (hitPoint).y - (obj->p).y; (normal).z = (hitPoint).z - (obj->p).z; };
{ float l = 1.f / sqrt(((normal).x * (normal).x + (normal).y * (normal).y + (normal).z * (normal).z)); { float k = (l); { (normal).x = k * (normal).x; (normal).y = k * (normal).y; (normal).z = k * (normal).z; } }; };
const float dp = ((normal).x * (currentRay.d).x + (normal).y * (currentRay.d).y + (normal).z * (currentRay.d).z);
Vec nl;
const float invSignDP = -1.f * sign(dp);
{ float k = (invSignDP); { (nl).x = k * (normal).x; (nl).y = k * (normal).y; (nl).z = k * (normal).z; } };
Vec eCol; { (eCol).x = (obj->e).x; (eCol).y = (obj->e).y; (eCol).z = (obj->e).z; };
if (!(((eCol).x == 0.f) && ((eCol).x == 0.f) && ((eCol).z == 0.f))) {
if (specularBounce) {
{ float k = (fabs(dp)); { (eCol).x = k * (eCol).x; (eCol).y = k * (eCol).y; (eCol).z = k * (eCol).z; } };
{ (eCol).x = (throughput).x * (eCol).x; (eCol).y = (throughput).y * (eCol).y; (eCol).z = (throughput).z * (eCol).z; };
{ (rad).x = (rad).x + (eCol).x; (rad).y = (rad).y + (eCol).y; (rad).z = (rad).z + (eCol).z; };
}
*result = rad;
return;
}
if (obj->refl == DIFF) {
specularBounce = 0;
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
Vec Ld;
SampleLights(spheres, sphereCount, seed0, seed1, &hitPoint, &nl, &Ld);
{ (Ld).x = (throughput).x * (Ld).x; (Ld).y = (throughput).y * (Ld).y; (Ld).z = (throughput).z * (Ld).z; };
{ (rad).x = (rad).x + (Ld).x; (rad).y = (rad).y + (Ld).y; (rad).z = (rad).z + (Ld).z; };
float r1 = 2.f * 3.14159265358979323846f * GetRandom(seed0, seed1);
float r2 = GetRandom(seed0, seed1);
float r2s = sqrt(r2);
Vec w; { (w).x = (nl).x; (w).y = (nl).y; (w).z = (nl).z; };
Vec u, a;
if (fabs(w.x) > .1f) {
{ (a).x = 0.f; (a).y = 1.f; (a).z = 0.f; };
} else {
{ (a).x = 1.f; (a).y = 0.f; (a).z = 0.f; };
}
{ (u).x = (a).y * (w).z - (a).z * (w).y; (u).y = (a).z * (w).x - (a).x * (w).z; (u).z = (a).x * (w).y - (a).y * (w).x; };
{ float l = 1.f / sqrt(((u).x * (u).x + (u).y * (u).y + (u).z * (u).z)); { float k = (l); { (u).x = k * (u).x; (u).y = k * (u).y; (u).z = k * (u).z; } }; };
Vec v;
{ (v).x = (w).y * (u).z - (w).z * (u).y; (v).y = (w).z * (u).x - (w).x * (u).z; (v).z = (w).x * (u).y - (w).y * (u).x; };
Vec newDir;
{ float k = (cos(r1) * r2s); { (u).x = k * (u).x; (u).y = k * (u).y; (u).z = k * (u).z; } };
{ float k = (sin(r1) * r2s); { (v).x = k * (v).x; (v).y = k * (v).y; (v).z = k * (v).z; } };
{ (newDir).x = (u).x + (v).x; (newDir).y = (u).y + (v).y; (newDir).z = (u).z + (v).z; };
{ float k = (sqrt(1 - r2)); { (w).x = k * (w).x; (w).y = k * (w).y; (w).z = k * (w).z; } };
{ (newDir).x = (newDir).x + (w).x; (newDir).y = (newDir).y + (w).y; (newDir).z = (newDir).z + (w).z; };
currentRay.o = hitPoint;
currentRay.d = newDir;
continue;
} else if (obj->refl == SPEC) {
specularBounce = 1;
Vec newDir;
{ float k = (2.f * ((normal).x * (currentRay.d).x + (normal).y * (currentRay.d).y + (normal).z * (currentRay.d).z)); { (newDir).x = k * (normal).x; (newDir).y = k * (normal).y; (newDir).z = k * (normal).z; } };
{ (newDir).x = (currentRay.d).x - (newDir).x; (newDir).y = (currentRay.d).y - (newDir).y; (newDir).z = (currentRay.d).z - (newDir).z; };
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = (hitPoint).x; ((currentRay).o).y = (hitPoint).y; ((currentRay).o).z = (hitPoint).z; }; { ((currentRay).d).x = (newDir).x; ((currentRay).d).y = (newDir).y; ((currentRay).d).z = (newDir).z; }; };
continue;
} else {
specularBounce = 1;
Vec newDir;
{ float k = (2.f * ((normal).x * (currentRay.d).x + (normal).y * (currentRay.d).y + (normal).z * (currentRay.d).z)); { (newDir).x = k * (normal).x; (newDir).y = k * (normal).y; (newDir).z = k * (normal).z; } };
{ (newDir).x = (currentRay.d).x - (newDir).x; (newDir).y = (currentRay.d).y - (newDir).y; (newDir).z = (currentRay.d).z - (newDir).z; };
Ray reflRay; { { ((reflRay).o).x = (hitPoint).x; ((reflRay).o).y = (hitPoint).y; ((reflRay).o).z = (hitPoint).z; }; { ((reflRay).d).x = (newDir).x; ((reflRay).d).y = (newDir).y; ((reflRay).d).z = (newDir).z; }; };
int into = (((normal).x * (nl).x + (normal).y * (nl).y + (normal).z * (nl).z) > 0);
float nc = 1.f;
float nt = 1.5f;
float nnt = into ? nc / nt : nt / nc;
float ddn = ((currentRay.d).x * (nl).x + (currentRay.d).y * (nl).y + (currentRay.d).z * (nl).z);
float cos2t = 1.f - nnt * nnt * (1.f - ddn * ddn);
if (cos2t < 0.f) {
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = ((reflRay).o).x; ((currentRay).o).y = ((reflRay).o).y; ((currentRay).o).z = ((reflRay).o).z; }; { ((currentRay).d).x = ((reflRay).d).x; ((currentRay).d).y = ((reflRay).d).y; ((currentRay).d).z = ((reflRay).d).z; }; };
continue;
}
float kk = (into ? 1 : -1) * (ddn * nnt + sqrt(cos2t));
Vec nkk;
{ float k = (kk); { (nkk).x = k * (normal).x; (nkk).y = k * (normal).y; (nkk).z = k * (normal).z; } };
Vec transDir;
{ float k = (nnt); { (transDir).x = k * (currentRay.d).x; (transDir).y = k * (currentRay.d).y; (transDir).z = k * (currentRay.d).z; } };
{ (transDir).x = (transDir).x - (nkk).x; (transDir).y = (transDir).y - (nkk).y; (transDir).z = (transDir).z - (nkk).z; };
{ float l = 1.f / sqrt(((transDir).x * (transDir).x + (transDir).y * (transDir).y + (transDir).z * (transDir).z)); { float k = (l); { (transDir).x = k * (transDir).x; (transDir).y = k * (transDir).y; (transDir).z = k * (transDir).z; } }; };
float a = nt - nc;
float b = nt + nc;
float R0 = a * a / (b * b);
float c = 1 - (into ? -ddn : ((transDir).x * (normal).x + (transDir).y * (normal).y + (transDir).z * (normal).z));
float Re = R0 + (1 - R0) * c * c * c * c*c;
float Tr = 1.f - Re;
float P = .25f + .5f * Re;
float RP = Re / P;
float TP = Tr / (1.f - P);
if (GetRandom(seed0, seed1) < P) {
{ float k = (RP); { (throughput).x = k * (throughput).x; (throughput).y = k * (throughput).y; (throughput).z = k * (throughput).z; } };
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = ((reflRay).o).x; ((currentRay).o).y = ((reflRay).o).y; ((currentRay).o).z = ((reflRay).o).z; }; { ((currentRay).d).x = ((reflRay).d).x; ((currentRay).d).y = ((reflRay).d).y; ((currentRay).d).z = ((reflRay).d).z; }; };
continue;
} else {
{ float k = (TP); { (throughput).x = k * (throughput).x; (throughput).y = k * (throughput).y; (throughput).z = k * (throughput).z; } };
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = (hitPoint).x; ((currentRay).o).y = (hitPoint).y; ((currentRay).o).z = (hitPoint).z; }; { ((currentRay).d).x = (transDir).x; ((currentRay).d).y = (transDir).y; ((currentRay).d).z = (transDir).z; }; };
continue;
}
}
}
}
static void RadianceDirectLighting(
__constant
const Sphere *spheres,
const unsigned int sphereCount,
const Ray *startRay,
unsigned int *seed0, unsigned int *seed1,
Vec *result) {
Ray currentRay; { { ((currentRay).o).x = ((*startRay).o).x; ((currentRay).o).y = ((*startRay).o).y; ((currentRay).o).z = ((*startRay).o).z; }; { ((currentRay).d).x = ((*startRay).d).x; ((currentRay).d).y = ((*startRay).d).y; ((currentRay).d).z = ((*startRay).d).z; }; };
Vec rad; { (rad).x = 0.f; (rad).y = 0.f; (rad).z = 0.f; };
Vec throughput; { (throughput).x = 1.f; (throughput).y = 1.f; (throughput).z = 1.f; };
unsigned int depth = 0;
int specularBounce = 1;
for (;; ++depth) {
if (depth > 6) {
*result = rad;
return;
}
float t;
unsigned int id = 0;
if (!Intersect(spheres, sphereCount, &currentRay, &t, &id)) {
*result = rad;
return;
}
__constant
const Sphere *obj = &spheres[id];
Vec hitPoint;
{ float k = (t); { (hitPoint).x = k * (currentRay.d).x; (hitPoint).y = k * (currentRay.d).y; (hitPoint).z = k * (currentRay.d).z; } };
{ (hitPoint).x = (currentRay.o).x + (hitPoint).x; (hitPoint).y = (currentRay.o).y + (hitPoint).y; (hitPoint).z = (currentRay.o).z + (hitPoint).z; };
Vec normal;
{ (normal).x = (hitPoint).x - (obj->p).x; (normal).y = (hitPoint).y - (obj->p).y; (normal).z = (hitPoint).z - (obj->p).z; };
{ float l = 1.f / sqrt(((normal).x * (normal).x + (normal).y * (normal).y + (normal).z * (normal).z)); { float k = (l); { (normal).x = k * (normal).x; (normal).y = k * (normal).y; (normal).z = k * (normal).z; } }; };
const float dp = ((normal).x * (currentRay.d).x + (normal).y * (currentRay.d).y + (normal).z * (currentRay.d).z);
Vec nl;
const float invSignDP = -1.f * sign(dp);
{ float k = (invSignDP); { (nl).x = k * (normal).x; (nl).y = k * (normal).y; (nl).z = k * (normal).z; } };
Vec eCol; { (eCol).x = (obj->e).x; (eCol).y = (obj->e).y; (eCol).z = (obj->e).z; };
if (!(((eCol).x == 0.f) && ((eCol).x == 0.f) && ((eCol).z == 0.f))) {
if (specularBounce) {
{ float k = (fabs(dp)); { (eCol).x = k * (eCol).x; (eCol).y = k * (eCol).y; (eCol).z = k * (eCol).z; } };
{ (eCol).x = (throughput).x * (eCol).x; (eCol).y = (throughput).y * (eCol).y; (eCol).z = (throughput).z * (eCol).z; };
{ (rad).x = (rad).x + (eCol).x; (rad).y = (rad).y + (eCol).y; (rad).z = (rad).z + (eCol).z; };
}
*result = rad;
return;
}
if (obj->refl == DIFF) {
specularBounce = 0;
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
Vec Ld;
SampleLights(spheres, sphereCount, seed0, seed1, &hitPoint, &nl, &Ld);
{ (Ld).x = (throughput).x * (Ld).x; (Ld).y = (throughput).y * (Ld).y; (Ld).z = (throughput).z * (Ld).z; };
{ (rad).x = (rad).x + (Ld).x; (rad).y = (rad).y + (Ld).y; (rad).z = (rad).z + (Ld).z; };
*result = rad;
return;
} else if (obj->refl == SPEC) {
specularBounce = 1;
Vec newDir;
{ float k = (2.f * ((normal).x * (currentRay.d).x + (normal).y * (currentRay.d).y + (normal).z * (currentRay.d).z)); { (newDir).x = k * (normal).x; (newDir).y = k * (normal).y; (newDir).z = k * (normal).z; } };
{ (newDir).x = (currentRay.d).x - (newDir).x; (newDir).y = (currentRay.d).y - (newDir).y; (newDir).z = (currentRay.d).z - (newDir).z; };
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = (hitPoint).x; ((currentRay).o).y = (hitPoint).y; ((currentRay).o).z = (hitPoint).z; }; { ((currentRay).d).x = (newDir).x; ((currentRay).d).y = (newDir).y; ((currentRay).d).z = (newDir).z; }; };
continue;
} else {
specularBounce = 1;
Vec newDir;
{ float k = (2.f * ((normal).x * (currentRay.d).x + (normal).y * (currentRay.d).y + (normal).z * (currentRay.d).z)); { (newDir).x = k * (normal).x; (newDir).y = k * (normal).y; (newDir).z = k * (normal).z; } };
{ (newDir).x = (currentRay.d).x - (newDir).x; (newDir).y = (currentRay.d).y - (newDir).y; (newDir).z = (currentRay.d).z - (newDir).z; };
Ray reflRay; { { ((reflRay).o).x = (hitPoint).x; ((reflRay).o).y = (hitPoint).y; ((reflRay).o).z = (hitPoint).z; }; { ((reflRay).d).x = (newDir).x; ((reflRay).d).y = (newDir).y; ((reflRay).d).z = (newDir).z; }; };
int into = (((normal).x * (nl).x + (normal).y * (nl).y + (normal).z * (nl).z) > 0);
float nc = 1.f;
float nt = 1.5f;
float nnt = into ? nc / nt : nt / nc;
float ddn = ((currentRay.d).x * (nl).x + (currentRay.d).y * (nl).y + (currentRay.d).z * (nl).z);
float cos2t = 1.f - nnt * nnt * (1.f - ddn * ddn);
if (cos2t < 0.f) {
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = ((reflRay).o).x; ((currentRay).o).y = ((reflRay).o).y; ((currentRay).o).z = ((reflRay).o).z; }; { ((currentRay).d).x = ((reflRay).d).x; ((currentRay).d).y = ((reflRay).d).y; ((currentRay).d).z = ((reflRay).d).z; }; };
continue;
}
float kk = (into ? 1 : -1) * (ddn * nnt + sqrt(cos2t));
Vec nkk;
{ float k = (kk); { (nkk).x = k * (normal).x; (nkk).y = k * (normal).y; (nkk).z = k * (normal).z; } };
Vec transDir;
{ float k = (nnt); { (transDir).x = k * (currentRay.d).x; (transDir).y = k * (currentRay.d).y; (transDir).z = k * (currentRay.d).z; } };
{ (transDir).x = (transDir).x - (nkk).x; (transDir).y = (transDir).y - (nkk).y; (transDir).z = (transDir).z - (nkk).z; };
{ float l = 1.f / sqrt(((transDir).x * (transDir).x + (transDir).y * (transDir).y + (transDir).z * (transDir).z)); { float k = (l); { (transDir).x = k * (transDir).x; (transDir).y = k * (transDir).y; (transDir).z = k * (transDir).z; } }; };
float a = nt - nc;
float b = nt + nc;
float R0 = a * a / (b * b);
float c = 1 - (into ? -ddn : ((transDir).x * (normal).x + (transDir).y * (normal).y + (transDir).z * (normal).z));
float Re = R0 + (1 - R0) * c * c * c * c*c;
float Tr = 1.f - Re;
float P = .25f + .5f * Re;
float RP = Re / P;
float TP = Tr / (1.f - P);
if (GetRandom(seed0, seed1) < P) {
{ float k = (RP); { (throughput).x = k * (throughput).x; (throughput).y = k * (throughput).y; (throughput).z = k * (throughput).z; } };
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = ((reflRay).o).x; ((currentRay).o).y = ((reflRay).o).y; ((currentRay).o).z = ((reflRay).o).z; }; { ((currentRay).d).x = ((reflRay).d).x; ((currentRay).d).y = ((reflRay).d).y; ((currentRay).d).z = ((reflRay).d).z; }; };
continue;
} else {
{ float k = (TP); { (throughput).x = k * (throughput).x; (throughput).y = k * (throughput).y; (throughput).z = k * (throughput).z; } };
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = (hitPoint).x; ((currentRay).o).y = (hitPoint).y; ((currentRay).o).z = (hitPoint).z; }; { ((currentRay).d).x = (transDir).x; ((currentRay).d).y = (transDir).y; ((currentRay).d).z = (transDir).z; }; };
continue;
}
}
}
}
# 28 "<stdin>" 2
static void GenerateCameraRay(__constant Camera *camera,
unsigned int *seed0, unsigned int *seed1,
const int width, const int height, const int x, const int y, Ray *ray) {
const float invWidth = 1.f / width;
const float invHeight = 1.f / height;
const float r1 = GetRandom(seed0, seed1) - .5f;
const float r2 = GetRandom(seed0, seed1) - .5f;
const float kcx = (x + r1) * invWidth - .5f;
const float kcy = (y + r2) * invHeight - .5f;
Vec rdir;
{ (rdir).x = camera->x.x * kcx + camera->y.x * kcy + camera->dir.x; (rdir).y = camera->x.y * kcx + camera->y.y * kcy + camera->dir.y; (rdir).z = camera->x.z * kcx + camera->y.z * kcy + camera->dir.z; };
Vec rorig;
{ float k = (0.1f); { (rorig).x = k * (rdir).x; (rorig).y = k * (rdir).y; (rorig).z = k * (rdir).z; } };
{ (rorig).x = (rorig).x + (camera->orig).x; (rorig).y = (rorig).y + (camera->orig).y; (rorig).z = (rorig).z + (camera->orig).z; }
{ float l = 1.f / sqrt(((rdir).x * (rdir).x + (rdir).y * (rdir).y + (rdir).z * (rdir).z)); { float k = (l); { (rdir).x = k * (rdir).x; (rdir).y = k * (rdir).y; (rdir).z = k * (rdir).z; } }; };
{ { ((*ray).o).x = (rorig).x; ((*ray).o).y = (rorig).y; ((*ray).o).z = (rorig).z; }; { ((*ray).d).x = (rdir).x; ((*ray).d).y = (rdir).y; ((*ray).d).z = (rdir).z; }; };
}
__kernel void RadianceGPU(
__global Vec *colors, __global unsigned int *seedsInput,
__constant Sphere *sphere, __constant Camera *camera,
const unsigned int sphereCount,
const int width, const int height,
const int currentSample,
__global int *pixels) {
const int gid = get_global_id(0);
const int gid2 = 2 * gid;
const int x = gid % width;
const int y = gid / width;
if (y >= height)
return;
unsigned int seed0 = seedsInput[gid2];
unsigned int seed1 = seedsInput[gid2 + 1];
Ray ray;
GenerateCameraRay(camera, &seed0, &seed1, width, height, x, y, &ray);
Vec r;
RadiancePathTracing(sphere, sphereCount, &ray, &seed0, &seed1, &r);
const int i = (height - y - 1) * width + x;
if (currentSample == 0) {
{ (colors[i]).x = (r).x; (colors[i]).y = (r).y; (colors[i]).z = (r).z; };
} else {
const float k1 = currentSample;
const float k2 = 1.f / (currentSample + 1.f);
colors[i].x = (colors[i].x * k1 + r.x) * k2;
colors[i].y = (colors[i].y * k1 + r.y) * k2;
colors[i].z = (colors[i].z * k1 + r.z) * k2;
}
pixels[y * width + x] = ((int)(pow(clamp(colors[i].x, 0.f, 1.f), 1.f / 2.2f) * 255.f + .5f)) |
(((int)(pow(clamp(colors[i].y, 0.f, 1.f), 1.f / 2.2f) * 255.f + .5f)) << 8) |
(((int)(pow(clamp(colors[i].z, 0.f, 1.f), 1.f / 2.2f) * 255.f + .5f)) << 16);
seedsInput[gid2] = seed0;
seedsInput[gid2 + 1] = seed1;
}

View File

@ -0,0 +1,586 @@
# 1 "<stdin>"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "<stdin>"
# 26 "<stdin>"
# 1 "camera.h" 1
# 27 "camera.h"
# 1 "vec.h" 1
# 27 "vec.h"
typedef struct {
float x, y, z;
} Vec;
# 28 "camera.h" 2
typedef struct {
Vec orig, target;
Vec dir, x, y;
} Camera;
# 27 "<stdin>" 2
# 1 "geomfunc.h" 1
# 27 "geomfunc.h"
# 1 "geom.h" 1
# 32 "geom.h"
typedef struct {
Vec o, d;
} Ray;
enum Refl {
DIFF, SPEC, REFR
};
typedef struct {
float rad;
Vec p, e, c;
enum Refl refl;
} Sphere;
# 28 "geomfunc.h" 2
# 1 "simplernd.h" 1
# 34 "simplernd.h"
static float GetRandom(unsigned int *seed0, unsigned int *seed1) {
*seed0 = 36969 * ((*seed0) & 65535) + ((*seed0) >> 16);
*seed1 = 18000 * ((*seed1) & 65535) + ((*seed1) >> 16);
unsigned int ires = ((*seed0) << 16) + (*seed1);
union {
float f;
unsigned int ui;
} res;
res.ui = (ires & 0x007fffff) | 0x40000000;
return (res.f - 2.f) / 2.f;
}
# 29 "geomfunc.h" 2
static float SphereIntersect(
__constant
const Sphere *s,
const Ray *r) {
Vec op;
{ (op).x = (s->p).x - (r->o).x; (op).y = (s->p).y - (r->o).y; (op).z = (s->p).z - (r->o).z; };
float b = ((op).x * (r->d).x + (op).y * (r->d).y + (op).z * (r->d).z);
float det = b * b - ((op).x * (op).x + (op).y * (op).y + (op).z * (op).z) + s->rad * s->rad;
if (det < 0.f)
return 0.f;
else
det = sqrt(det);
float t = b - det;
if (t > 0.01f)
return t;
else {
t = b + det;
if (t > 0.01f)
return t;
else
return 0.f;
}
}
static void UniformSampleSphere(const float u1, const float u2, Vec *v) {
const float zz = 1.f - 2.f * u1;
const float r = sqrt(max(0.f, 1.f - zz * zz));
const float phi = 2.f * 3.14159265358979323846f * u2;
const float xx = r * cos(phi);
const float yy = r * sin(phi);
{ (*v).x = xx; (*v).y = yy; (*v).z = zz; };
}
static int Intersect(
__constant
const Sphere *spheres,
const unsigned int sphereCount,
const Ray *r,
float *t,
unsigned int *id) {
float inf = (*t) = 1e20f;
unsigned int i = sphereCount;
for (; i--;) {
const float d = SphereIntersect(&spheres[i], r);
if ((d != 0.f) && (d < *t)) {
*t = d;
*id = i;
}
}
return (*t < inf);
}
static int IntersectP(
__constant
const Sphere *spheres,
const unsigned int sphereCount,
const Ray *r,
const float maxt) {
unsigned int i = sphereCount;
for (; i--;) {
const float d = SphereIntersect(&spheres[i], r);
if ((d != 0.f) && (d < maxt))
return 1;
}
return 0;
}
static void SampleLights(
__constant
const Sphere *spheres,
const unsigned int sphereCount,
unsigned int *seed0, unsigned int *seed1,
const Vec *hitPoint,
const Vec *normal,
Vec *result) {
{ (*result).x = 0.f; (*result).y = 0.f; (*result).z = 0.f; };
unsigned int i;
for (i = 0; i < sphereCount; i++) {
__constant
const Sphere *light = &spheres[i];
if (!(((light->e).x == 0.f) && ((light->e).x == 0.f) && ((light->e).z == 0.f))) {
Ray shadowRay;
shadowRay.o = *hitPoint;
Vec unitSpherePoint;
UniformSampleSphere(GetRandom(seed0, seed1), GetRandom(seed0, seed1), &unitSpherePoint);
Vec spherePoint;
{ float k = (light->rad); { (spherePoint).x = k * (unitSpherePoint).x; (spherePoint).y = k * (unitSpherePoint).y; (spherePoint).z = k * (unitSpherePoint).z; } };
{ (spherePoint).x = (spherePoint).x + (light->p).x; (spherePoint).y = (spherePoint).y + (light->p).y; (spherePoint).z = (spherePoint).z + (light->p).z; };
{ (shadowRay.d).x = (spherePoint).x - (*hitPoint).x; (shadowRay.d).y = (spherePoint).y - (*hitPoint).y; (shadowRay.d).z = (spherePoint).z - (*hitPoint).z; };
const float len = sqrt(((shadowRay.d).x * (shadowRay.d).x + (shadowRay.d).y * (shadowRay.d).y + (shadowRay.d).z * (shadowRay.d).z));
{ float k = (1.f / len); { (shadowRay.d).x = k * (shadowRay.d).x; (shadowRay.d).y = k * (shadowRay.d).y; (shadowRay.d).z = k * (shadowRay.d).z; } };
float wo = ((shadowRay.d).x * (unitSpherePoint).x + (shadowRay.d).y * (unitSpherePoint).y + (shadowRay.d).z * (unitSpherePoint).z);
if (wo > 0.f) {
continue;
} else
wo = -wo;
const float wi = ((shadowRay.d).x * (*normal).x + (shadowRay.d).y * (*normal).y + (shadowRay.d).z * (*normal).z);
if ((wi > 0.f) && (!IntersectP(spheres, sphereCount, &shadowRay, len - 0.01f))) {
Vec c; { (c).x = (light->e).x; (c).y = (light->e).y; (c).z = (light->e).z; };
const float s = (4.f * 3.14159265358979323846f * light->rad * light->rad) * wi * wo / (len *len);
{ float k = (s); { (c).x = k * (c).x; (c).y = k * (c).y; (c).z = k * (c).z; } };
{ (*result).x = (*result).x + (c).x; (*result).y = (*result).y + (c).y; (*result).z = (*result).z + (c).z; };
}
}
}
}
static void RadiancePathTracing(
__constant
const Sphere *spheres,
const unsigned int sphereCount,
const Ray *startRay,
unsigned int *seed0, unsigned int *seed1,
Vec *result) {
Ray currentRay; { { ((currentRay).o).x = ((*startRay).o).x; ((currentRay).o).y = ((*startRay).o).y; ((currentRay).o).z = ((*startRay).o).z; }; { ((currentRay).d).x = ((*startRay).d).x; ((currentRay).d).y = ((*startRay).d).y; ((currentRay).d).z = ((*startRay).d).z; }; };
Vec rad; { (rad).x = 0.f; (rad).y = 0.f; (rad).z = 0.f; };
Vec throughput; { (throughput).x = 1.f; (throughput).y = 1.f; (throughput).z = 1.f; };
unsigned int depth = 0;
int specularBounce = 1;
for (;; ++depth) {
if (depth > 6) {
*result = rad;
return;
}
float t;
unsigned int id = 0;
if (!Intersect(spheres, sphereCount, &currentRay, &t, &id)) {
*result = rad;
return;
}
__constant
const Sphere *obj = &spheres[id];
Vec hitPoint;
{ float k = (t); { (hitPoint).x = k * (currentRay.d).x; (hitPoint).y = k * (currentRay.d).y; (hitPoint).z = k * (currentRay.d).z; } };
{ (hitPoint).x = (currentRay.o).x + (hitPoint).x; (hitPoint).y = (currentRay.o).y + (hitPoint).y; (hitPoint).z = (currentRay.o).z + (hitPoint).z; };
Vec normal;
{ (normal).x = (hitPoint).x - (obj->p).x; (normal).y = (hitPoint).y - (obj->p).y; (normal).z = (hitPoint).z - (obj->p).z; };
{ float l = 1.f / sqrt(((normal).x * (normal).x + (normal).y * (normal).y + (normal).z * (normal).z)); { float k = (l); { (normal).x = k * (normal).x; (normal).y = k * (normal).y; (normal).z = k * (normal).z; } }; };
const float dp = ((normal).x * (currentRay.d).x + (normal).y * (currentRay.d).y + (normal).z * (currentRay.d).z);
Vec nl;
const float invSignDP = -1.f * sign(dp);
{ float k = (invSignDP); { (nl).x = k * (normal).x; (nl).y = k * (normal).y; (nl).z = k * (normal).z; } };
Vec eCol; { (eCol).x = (obj->e).x; (eCol).y = (obj->e).y; (eCol).z = (obj->e).z; };
if (!(((eCol).x == 0.f) && ((eCol).x == 0.f) && ((eCol).z == 0.f))) {
if (specularBounce) {
{ float k = (fabs(dp)); { (eCol).x = k * (eCol).x; (eCol).y = k * (eCol).y; (eCol).z = k * (eCol).z; } };
{ (eCol).x = (throughput).x * (eCol).x; (eCol).y = (throughput).y * (eCol).y; (eCol).z = (throughput).z * (eCol).z; };
{ (rad).x = (rad).x + (eCol).x; (rad).y = (rad).y + (eCol).y; (rad).z = (rad).z + (eCol).z; };
}
*result = rad;
return;
}
if (obj->refl == DIFF) {
specularBounce = 0;
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
Vec Ld;
SampleLights(spheres, sphereCount, seed0, seed1, &hitPoint, &nl, &Ld);
{ (Ld).x = (throughput).x * (Ld).x; (Ld).y = (throughput).y * (Ld).y; (Ld).z = (throughput).z * (Ld).z; };
{ (rad).x = (rad).x + (Ld).x; (rad).y = (rad).y + (Ld).y; (rad).z = (rad).z + (Ld).z; };
float r1 = 2.f * 3.14159265358979323846f * GetRandom(seed0, seed1);
float r2 = GetRandom(seed0, seed1);
float r2s = sqrt(r2);
Vec w; { (w).x = (nl).x; (w).y = (nl).y; (w).z = (nl).z; };
Vec u, a;
if (fabs(w.x) > .1f) {
{ (a).x = 0.f; (a).y = 1.f; (a).z = 0.f; };
} else {
{ (a).x = 1.f; (a).y = 0.f; (a).z = 0.f; };
}
{ (u).x = (a).y * (w).z - (a).z * (w).y; (u).y = (a).z * (w).x - (a).x * (w).z; (u).z = (a).x * (w).y - (a).y * (w).x; };
{ float l = 1.f / sqrt(((u).x * (u).x + (u).y * (u).y + (u).z * (u).z)); { float k = (l); { (u).x = k * (u).x; (u).y = k * (u).y; (u).z = k * (u).z; } }; };
Vec v;
{ (v).x = (w).y * (u).z - (w).z * (u).y; (v).y = (w).z * (u).x - (w).x * (u).z; (v).z = (w).x * (u).y - (w).y * (u).x; };
Vec newDir;
{ float k = (cos(r1) * r2s); { (u).x = k * (u).x; (u).y = k * (u).y; (u).z = k * (u).z; } };
{ float k = (sin(r1) * r2s); { (v).x = k * (v).x; (v).y = k * (v).y; (v).z = k * (v).z; } };
{ (newDir).x = (u).x + (v).x; (newDir).y = (u).y + (v).y; (newDir).z = (u).z + (v).z; };
{ float k = (sqrt(1 - r2)); { (w).x = k * (w).x; (w).y = k * (w).y; (w).z = k * (w).z; } };
{ (newDir).x = (newDir).x + (w).x; (newDir).y = (newDir).y + (w).y; (newDir).z = (newDir).z + (w).z; };
currentRay.o = hitPoint;
currentRay.d = newDir;
continue;
} else if (obj->refl == SPEC) {
specularBounce = 1;
Vec newDir;
{ float k = (2.f * ((normal).x * (currentRay.d).x + (normal).y * (currentRay.d).y + (normal).z * (currentRay.d).z)); { (newDir).x = k * (normal).x; (newDir).y = k * (normal).y; (newDir).z = k * (normal).z; } };
{ (newDir).x = (currentRay.d).x - (newDir).x; (newDir).y = (currentRay.d).y - (newDir).y; (newDir).z = (currentRay.d).z - (newDir).z; };
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = (hitPoint).x; ((currentRay).o).y = (hitPoint).y; ((currentRay).o).z = (hitPoint).z; }; { ((currentRay).d).x = (newDir).x; ((currentRay).d).y = (newDir).y; ((currentRay).d).z = (newDir).z; }; };
continue;
} else {
specularBounce = 1;
Vec newDir;
{ float k = (2.f * ((normal).x * (currentRay.d).x + (normal).y * (currentRay.d).y + (normal).z * (currentRay.d).z)); { (newDir).x = k * (normal).x; (newDir).y = k * (normal).y; (newDir).z = k * (normal).z; } };
{ (newDir).x = (currentRay.d).x - (newDir).x; (newDir).y = (currentRay.d).y - (newDir).y; (newDir).z = (currentRay.d).z - (newDir).z; };
Ray reflRay; { { ((reflRay).o).x = (hitPoint).x; ((reflRay).o).y = (hitPoint).y; ((reflRay).o).z = (hitPoint).z; }; { ((reflRay).d).x = (newDir).x; ((reflRay).d).y = (newDir).y; ((reflRay).d).z = (newDir).z; }; };
int into = (((normal).x * (nl).x + (normal).y * (nl).y + (normal).z * (nl).z) > 0);
float nc = 1.f;
float nt = 1.5f;
float nnt = into ? nc / nt : nt / nc;
float ddn = ((currentRay.d).x * (nl).x + (currentRay.d).y * (nl).y + (currentRay.d).z * (nl).z);
float cos2t = 1.f - nnt * nnt * (1.f - ddn * ddn);
if (cos2t < 0.f) {
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = ((reflRay).o).x; ((currentRay).o).y = ((reflRay).o).y; ((currentRay).o).z = ((reflRay).o).z; }; { ((currentRay).d).x = ((reflRay).d).x; ((currentRay).d).y = ((reflRay).d).y; ((currentRay).d).z = ((reflRay).d).z; }; };
continue;
}
float kk = (into ? 1 : -1) * (ddn * nnt + sqrt(cos2t));
Vec nkk;
{ float k = (kk); { (nkk).x = k * (normal).x; (nkk).y = k * (normal).y; (nkk).z = k * (normal).z; } };
Vec transDir;
{ float k = (nnt); { (transDir).x = k * (currentRay.d).x; (transDir).y = k * (currentRay.d).y; (transDir).z = k * (currentRay.d).z; } };
{ (transDir).x = (transDir).x - (nkk).x; (transDir).y = (transDir).y - (nkk).y; (transDir).z = (transDir).z - (nkk).z; };
{ float l = 1.f / sqrt(((transDir).x * (transDir).x + (transDir).y * (transDir).y + (transDir).z * (transDir).z)); { float k = (l); { (transDir).x = k * (transDir).x; (transDir).y = k * (transDir).y; (transDir).z = k * (transDir).z; } }; };
float a = nt - nc;
float b = nt + nc;
float R0 = a * a / (b * b);
float c = 1 - (into ? -ddn : ((transDir).x * (normal).x + (transDir).y * (normal).y + (transDir).z * (normal).z));
float Re = R0 + (1 - R0) * c * c * c * c*c;
float Tr = 1.f - Re;
float P = .25f + .5f * Re;
float RP = Re / P;
float TP = Tr / (1.f - P);
if (GetRandom(seed0, seed1) < P) {
{ float k = (RP); { (throughput).x = k * (throughput).x; (throughput).y = k * (throughput).y; (throughput).z = k * (throughput).z; } };
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = ((reflRay).o).x; ((currentRay).o).y = ((reflRay).o).y; ((currentRay).o).z = ((reflRay).o).z; }; { ((currentRay).d).x = ((reflRay).d).x; ((currentRay).d).y = ((reflRay).d).y; ((currentRay).d).z = ((reflRay).d).z; }; };
continue;
} else {
{ float k = (TP); { (throughput).x = k * (throughput).x; (throughput).y = k * (throughput).y; (throughput).z = k * (throughput).z; } };
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = (hitPoint).x; ((currentRay).o).y = (hitPoint).y; ((currentRay).o).z = (hitPoint).z; }; { ((currentRay).d).x = (transDir).x; ((currentRay).d).y = (transDir).y; ((currentRay).d).z = (transDir).z; }; };
continue;
}
}
}
}
static void RadianceDirectLighting(
__constant
const Sphere *spheres,
const unsigned int sphereCount,
const Ray *startRay,
unsigned int *seed0, unsigned int *seed1,
Vec *result) {
Ray currentRay; { { ((currentRay).o).x = ((*startRay).o).x; ((currentRay).o).y = ((*startRay).o).y; ((currentRay).o).z = ((*startRay).o).z; }; { ((currentRay).d).x = ((*startRay).d).x; ((currentRay).d).y = ((*startRay).d).y; ((currentRay).d).z = ((*startRay).d).z; }; };
Vec rad; { (rad).x = 0.f; (rad).y = 0.f; (rad).z = 0.f; };
Vec throughput; { (throughput).x = 1.f; (throughput).y = 1.f; (throughput).z = 1.f; };
unsigned int depth = 0;
int specularBounce = 1;
for (;; ++depth) {
if (depth > 6) {
*result = rad;
return;
}
float t;
unsigned int id = 0;
if (!Intersect(spheres, sphereCount, &currentRay, &t, &id)) {
*result = rad;
return;
}
__constant
const Sphere *obj = &spheres[id];
Vec hitPoint;
{ float k = (t); { (hitPoint).x = k * (currentRay.d).x; (hitPoint).y = k * (currentRay.d).y; (hitPoint).z = k * (currentRay.d).z; } };
{ (hitPoint).x = (currentRay.o).x + (hitPoint).x; (hitPoint).y = (currentRay.o).y + (hitPoint).y; (hitPoint).z = (currentRay.o).z + (hitPoint).z; };
Vec normal;
{ (normal).x = (hitPoint).x - (obj->p).x; (normal).y = (hitPoint).y - (obj->p).y; (normal).z = (hitPoint).z - (obj->p).z; };
{ float l = 1.f / sqrt(((normal).x * (normal).x + (normal).y * (normal).y + (normal).z * (normal).z)); { float k = (l); { (normal).x = k * (normal).x; (normal).y = k * (normal).y; (normal).z = k * (normal).z; } }; };
const float dp = ((normal).x * (currentRay.d).x + (normal).y * (currentRay.d).y + (normal).z * (currentRay.d).z);
Vec nl;
const float invSignDP = -1.f * sign(dp);
{ float k = (invSignDP); { (nl).x = k * (normal).x; (nl).y = k * (normal).y; (nl).z = k * (normal).z; } };
Vec eCol; { (eCol).x = (obj->e).x; (eCol).y = (obj->e).y; (eCol).z = (obj->e).z; };
if (!(((eCol).x == 0.f) && ((eCol).x == 0.f) && ((eCol).z == 0.f))) {
if (specularBounce) {
{ float k = (fabs(dp)); { (eCol).x = k * (eCol).x; (eCol).y = k * (eCol).y; (eCol).z = k * (eCol).z; } };
{ (eCol).x = (throughput).x * (eCol).x; (eCol).y = (throughput).y * (eCol).y; (eCol).z = (throughput).z * (eCol).z; };
{ (rad).x = (rad).x + (eCol).x; (rad).y = (rad).y + (eCol).y; (rad).z = (rad).z + (eCol).z; };
}
*result = rad;
return;
}
if (obj->refl == DIFF) {
specularBounce = 0;
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
Vec Ld;
SampleLights(spheres, sphereCount, seed0, seed1, &hitPoint, &nl, &Ld);
{ (Ld).x = (throughput).x * (Ld).x; (Ld).y = (throughput).y * (Ld).y; (Ld).z = (throughput).z * (Ld).z; };
{ (rad).x = (rad).x + (Ld).x; (rad).y = (rad).y + (Ld).y; (rad).z = (rad).z + (Ld).z; };
*result = rad;
return;
} else if (obj->refl == SPEC) {
specularBounce = 1;
Vec newDir;
{ float k = (2.f * ((normal).x * (currentRay.d).x + (normal).y * (currentRay.d).y + (normal).z * (currentRay.d).z)); { (newDir).x = k * (normal).x; (newDir).y = k * (normal).y; (newDir).z = k * (normal).z; } };
{ (newDir).x = (currentRay.d).x - (newDir).x; (newDir).y = (currentRay.d).y - (newDir).y; (newDir).z = (currentRay.d).z - (newDir).z; };
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = (hitPoint).x; ((currentRay).o).y = (hitPoint).y; ((currentRay).o).z = (hitPoint).z; }; { ((currentRay).d).x = (newDir).x; ((currentRay).d).y = (newDir).y; ((currentRay).d).z = (newDir).z; }; };
continue;
} else {
specularBounce = 1;
Vec newDir;
{ float k = (2.f * ((normal).x * (currentRay.d).x + (normal).y * (currentRay.d).y + (normal).z * (currentRay.d).z)); { (newDir).x = k * (normal).x; (newDir).y = k * (normal).y; (newDir).z = k * (normal).z; } };
{ (newDir).x = (currentRay.d).x - (newDir).x; (newDir).y = (currentRay.d).y - (newDir).y; (newDir).z = (currentRay.d).z - (newDir).z; };
Ray reflRay; { { ((reflRay).o).x = (hitPoint).x; ((reflRay).o).y = (hitPoint).y; ((reflRay).o).z = (hitPoint).z; }; { ((reflRay).d).x = (newDir).x; ((reflRay).d).y = (newDir).y; ((reflRay).d).z = (newDir).z; }; };
int into = (((normal).x * (nl).x + (normal).y * (nl).y + (normal).z * (nl).z) > 0);
float nc = 1.f;
float nt = 1.5f;
float nnt = into ? nc / nt : nt / nc;
float ddn = ((currentRay.d).x * (nl).x + (currentRay.d).y * (nl).y + (currentRay.d).z * (nl).z);
float cos2t = 1.f - nnt * nnt * (1.f - ddn * ddn);
if (cos2t < 0.f) {
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = ((reflRay).o).x; ((currentRay).o).y = ((reflRay).o).y; ((currentRay).o).z = ((reflRay).o).z; }; { ((currentRay).d).x = ((reflRay).d).x; ((currentRay).d).y = ((reflRay).d).y; ((currentRay).d).z = ((reflRay).d).z; }; };
continue;
}
float kk = (into ? 1 : -1) * (ddn * nnt + sqrt(cos2t));
Vec nkk;
{ float k = (kk); { (nkk).x = k * (normal).x; (nkk).y = k * (normal).y; (nkk).z = k * (normal).z; } };
Vec transDir;
{ float k = (nnt); { (transDir).x = k * (currentRay.d).x; (transDir).y = k * (currentRay.d).y; (transDir).z = k * (currentRay.d).z; } };
{ (transDir).x = (transDir).x - (nkk).x; (transDir).y = (transDir).y - (nkk).y; (transDir).z = (transDir).z - (nkk).z; };
{ float l = 1.f / sqrt(((transDir).x * (transDir).x + (transDir).y * (transDir).y + (transDir).z * (transDir).z)); { float k = (l); { (transDir).x = k * (transDir).x; (transDir).y = k * (transDir).y; (transDir).z = k * (transDir).z; } }; };
float a = nt - nc;
float b = nt + nc;
float R0 = a * a / (b * b);
float c = 1 - (into ? -ddn : ((transDir).x * (normal).x + (transDir).y * (normal).y + (transDir).z * (normal).z));
float Re = R0 + (1 - R0) * c * c * c * c*c;
float Tr = 1.f - Re;
float P = .25f + .5f * Re;
float RP = Re / P;
float TP = Tr / (1.f - P);
if (GetRandom(seed0, seed1) < P) {
{ float k = (RP); { (throughput).x = k * (throughput).x; (throughput).y = k * (throughput).y; (throughput).z = k * (throughput).z; } };
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = ((reflRay).o).x; ((currentRay).o).y = ((reflRay).o).y; ((currentRay).o).z = ((reflRay).o).z; }; { ((currentRay).d).x = ((reflRay).d).x; ((currentRay).d).y = ((reflRay).d).y; ((currentRay).d).z = ((reflRay).d).z; }; };
continue;
} else {
{ float k = (TP); { (throughput).x = k * (throughput).x; (throughput).y = k * (throughput).y; (throughput).z = k * (throughput).z; } };
{ (throughput).x = (throughput).x * (obj->c).x; (throughput).y = (throughput).y * (obj->c).y; (throughput).z = (throughput).z * (obj->c).z; };
{ { ((currentRay).o).x = (hitPoint).x; ((currentRay).o).y = (hitPoint).y; ((currentRay).o).z = (hitPoint).z; }; { ((currentRay).d).x = (transDir).x; ((currentRay).d).y = (transDir).y; ((currentRay).d).z = (transDir).z; }; };
continue;
}
}
}
}
# 28 "<stdin>" 2
static void GenerateCameraRay(__constant Camera *camera,
unsigned int *seed0, unsigned int *seed1,
const int width, const int height, const int x, const int y, Ray *ray) {
const float invWidth = 1.f / width;
const float invHeight = 1.f / height;
const float r1 = GetRandom(seed0, seed1) - .5f;
const float r2 = GetRandom(seed0, seed1) - .5f;
const float kcx = (x + r1) * invWidth - .5f;
const float kcy = (y + r2) * invHeight - .5f;
Vec rdir;
{ (rdir).x = camera->x.x * kcx + camera->y.x * kcy + camera->dir.x; (rdir).y = camera->x.y * kcx + camera->y.y * kcy + camera->dir.y; (rdir).z = camera->x.z * kcx + camera->y.z * kcy + camera->dir.z; };
Vec rorig;
{ float k = (0.1f); { (rorig).x = k * (rdir).x; (rorig).y = k * (rdir).y; (rorig).z = k * (rdir).z; } };
{ (rorig).x = (rorig).x + (camera->orig).x; (rorig).y = (rorig).y + (camera->orig).y; (rorig).z = (rorig).z + (camera->orig).z; }
{ float l = 1.f / sqrt(((rdir).x * (rdir).x + (rdir).y * (rdir).y + (rdir).z * (rdir).z)); { float k = (l); { (rdir).x = k * (rdir).x; (rdir).y = k * (rdir).y; (rdir).z = k * (rdir).z; } }; };
{ { ((*ray).o).x = (rorig).x; ((*ray).o).y = (rorig).y; ((*ray).o).z = (rorig).z; }; { ((*ray).d).x = (rdir).x; ((*ray).d).y = (rdir).y; ((*ray).d).z = (rdir).z; }; };
}
__kernel void RadianceGPU(
__global Vec *colors, __global unsigned int *seedsInput,
__constant Sphere *sphere, __constant Camera *camera,
const unsigned int sphereCount,
const int width, const int height,
const int currentSample,
__global int *pixels) {
const int gid = get_global_id(0);
const int gid2 = 2 * gid;
const int x = gid % width;
const int y = gid / width;
if (y >= height)
return;
unsigned int seed0 = seedsInput[gid2];
unsigned int seed1 = seedsInput[gid2 + 1];
Ray ray;
GenerateCameraRay(camera, &seed0, &seed1, width, height, x, y, &ray);
Vec r;
RadianceDirectLighting(sphere, sphereCount, &ray, &seed0, &seed1, &r);
const int i = (height - y - 1) * width + x;
if (currentSample == 0) {
{ (colors[i]).x = (r).x; (colors[i]).y = (r).y; (colors[i]).z = (r).z; };
} else {
const float k1 = currentSample;
const float k2 = 1.f / (currentSample + 1.f);
colors[i].x = (colors[i].x * k1 + r.x) * k2;
colors[i].y = (colors[i].y * k1 + r.y) * k2;
colors[i].z = (colors[i].z * k1 + r.z) * k2;
}
pixels[y * width + x] = ((int)(pow(clamp(colors[i].x, 0.f, 1.f), 1.f / 2.2f) * 255.f + .5f)) |
(((int)(pow(clamp(colors[i].y, 0.f, 1.f), 1.f / 2.2f) * 255.f + .5f)) << 8) |
(((int)(pow(clamp(colors[i].z, 0.f, 1.f), 1.f / 2.2f) * 255.f + .5f)) << 16);
seedsInput[gid2] = seed0;
seedsInput[gid2 + 1] = seed1;
}

97
rendering_kernel.cl Normal file
View File

@ -0,0 +1,97 @@
/*
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define GPU_KERNEL
#include "camera.h"
#include "geomfunc.h"
static void GenerateCameraRay(OCL_CONSTANT_BUFFER Camera *camera,
unsigned int *seed0, unsigned int *seed1,
const int width, const int height, const int x, const int y, Ray *ray) {
const float invWidth = 1.f / width;
const float invHeight = 1.f / height;
const float r1 = GetRandom(seed0, seed1) - .5f;
const float r2 = GetRandom(seed0, seed1) - .5f;
const float kcx = (x + r1) * invWidth - .5f;
const float kcy = (y + r2) * invHeight - .5f;
Vec rdir;
vinit(rdir,
camera->x.x * kcx + camera->y.x * kcy + camera->dir.x,
camera->x.y * kcx + camera->y.y * kcy + camera->dir.y,
camera->x.z * kcx + camera->y.z * kcy + camera->dir.z);
Vec rorig;
vsmul(rorig, 0.1f, rdir);
vadd(rorig, rorig, camera->orig)
vnorm(rdir);
rinit(*ray, rorig, rdir);
}
__kernel void RadianceGPU(
__global Vec *colors, __global unsigned int *seedsInput,
OCL_CONSTANT_BUFFER Sphere *sphere, OCL_CONSTANT_BUFFER Camera *camera,
const unsigned int sphereCount,
const int width, const int height,
const int currentSample,
__global int *pixels) {
const int gid = get_global_id(0);
const int gid2 = 2 * gid;
const int x = gid % width;
const int y = gid / width;
/* Check if we have to do something */
if (y >= height)
return;
/* LordCRC: move seed to local store */
unsigned int seed0 = seedsInput[gid2];
unsigned int seed1 = seedsInput[gid2 + 1];
Ray ray;
GenerateCameraRay(camera, &seed0, &seed1, width, height, x, y, &ray);
Vec r;
RadiancePathTracing(sphere, sphereCount, &ray, &seed0, &seed1, &r);
const int i = (height - y - 1) * width + x;
if (currentSample == 0) {
// Jens's patch for MacOS
vassign(colors[i], r);
} else {
const float k1 = currentSample;
const float k2 = 1.f / (currentSample + 1.f);
colors[i].x = (colors[i].x * k1 + r.x) * k2;
colors[i].y = (colors[i].y * k1 + r.y) * k2;
colors[i].z = (colors[i].z * k1 + r.z) * k2;
}
pixels[y * width + x] = toInt(colors[i].x) |
(toInt(colors[i].y) << 8) |
(toInt(colors[i].z) << 16);
seedsInput[gid2] = seed0;
seedsInput[gid2 + 1] = seed1;
}

97
rendering_kernel_dl.cl Normal file
View File

@ -0,0 +1,97 @@
/*
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#define GPU_KERNEL
#include "camera.h"
#include "geomfunc.h"
static void GenerateCameraRay(OCL_CONSTANT_BUFFER Camera *camera,
unsigned int *seed0, unsigned int *seed1,
const int width, const int height, const int x, const int y, Ray *ray) {
const float invWidth = 1.f / width;
const float invHeight = 1.f / height;
const float r1 = GetRandom(seed0, seed1) - .5f;
const float r2 = GetRandom(seed0, seed1) - .5f;
const float kcx = (x + r1) * invWidth - .5f;
const float kcy = (y + r2) * invHeight - .5f;
Vec rdir;
vinit(rdir,
camera->x.x * kcx + camera->y.x * kcy + camera->dir.x,
camera->x.y * kcx + camera->y.y * kcy + camera->dir.y,
camera->x.z * kcx + camera->y.z * kcy + camera->dir.z);
Vec rorig;
vsmul(rorig, 0.1f, rdir);
vadd(rorig, rorig, camera->orig)
vnorm(rdir);
rinit(*ray, rorig, rdir);
}
__kernel void RadianceGPU(
__global Vec *colors, __global unsigned int *seedsInput,
OCL_CONSTANT_BUFFER Sphere *sphere, OCL_CONSTANT_BUFFER Camera *camera,
const unsigned int sphereCount,
const int width, const int height,
const int currentSample,
__global int *pixels) {
const int gid = get_global_id(0);
const int gid2 = 2 * gid;
const int x = gid % width;
const int y = gid / width;
/* Check if we have to do something */
if (y >= height)
return;
/* LordCRC: move seed to local store */
unsigned int seed0 = seedsInput[gid2];
unsigned int seed1 = seedsInput[gid2 + 1];
Ray ray;
GenerateCameraRay(camera, &seed0, &seed1, width, height, x, y, &ray);
Vec r;
RadianceDirectLighting(sphere, sphereCount, &ray, &seed0, &seed1, &r);
const int i = (height - y - 1) * width + x;
if (currentSample == 0) {
// Jens's patch for MacOS
vassign(colors[i], r);
} else {
const float k1 = currentSample;
const float k2 = 1.f / (currentSample + 1.f);
colors[i].x = (colors[i].x * k1 + r.x) * k2;
colors[i].y = (colors[i].y * k1 + r.y) * k2;
colors[i].z = (colors[i].z * k1 + r.z) * k2;
}
pixels[y * width + x] = toInt(colors[i].x) |
(toInt(colors[i].y) << 8) |
(toInt(colors[i].z) << 16);
seedsInput[gid2] = seed0;
seedsInput[gid2 + 1] = seed1;
}

53
scene.h Normal file
View File

@ -0,0 +1,53 @@
/*
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _SCENE_H
#define _SCENE_H
#include "geomfunc.h"
#define WALL_RAD 1e4f
static Sphere CornellSpheres[] = { /* Scene: radius, position, emission, color, material */
{ WALL_RAD, {WALL_RAD + 1.f, 40.8f, 81.6f}, {0.f, 0.f, 0.f}, {.75f, .25f, .25f}, DIFF }, /* Left */
{ WALL_RAD, {-WALL_RAD + 99.f, 40.8f, 81.6f}, {0.f, 0.f, 0.f}, {.25f, .25f, .75f}, DIFF }, /* Rght */
{ WALL_RAD, {50.f, 40.8f, WALL_RAD}, {0.f, 0.f, 0.f}, {.75f, .75f, .75f}, DIFF }, /* Back */
{ WALL_RAD, {50.f, 40.8f, -WALL_RAD + 270.f}, {0.f, 0.f, 0.f}, {0.f, 0.f, 0.f}, DIFF }, /* Frnt */
{ WALL_RAD, {50.f, WALL_RAD, 81.6f}, {0.f, 0.f, 0.f}, {.75f, .75f, .75f}, DIFF }, /* Botm */
{ WALL_RAD, {50.f, -WALL_RAD + 81.6f, 81.6f}, {0.f, 0.f, 0.f}, {.75f, .75f, .75f}, DIFF }, /* Top */
{ 16.5f, {27.f, 16.5f, 47.f}, {0.f, 0.f, 0.f}, {.9f, .9f, .9f}, SPEC }, /* Mirr */
{ 16.5f, {73.f, 16.5f, 78.f}, {0.f, 0.f, 0.f}, {.9f, .9f, .9f}, REFR }, /* Glas */
{ 7.f, {50.f, 81.6f - 15.f, 81.6f}, {12.f, 12.f, 12.f}, {0.f, 0.f, 0.f}, DIFF } /* Lite */
};
#ifdef SCENE_TEST
static const Sphere spheres[] = { /* Scene: radius, position, emission, color, material */
{ 1000.f, {0.f, -1000.f, 0.f}, {0.f, 0.f, 0.f}, {.75f, .75f, .75f}, DIFF }, /* Ground */
{ 15.f, {10.f, 15.f, 0.0f}, {0.f, 0.f, 0.f}, {.75f, 0.f, 0.f}, DIFF }, /* Red */
{ 20.f, {-40.f, 20.f, 0.0f}, {0.f, 0.f, 0.f}, {0.f, 0.f, .75f}, DIFF }, /* Blue */
{ 10.f, {-5.f, 10.f, 20.0f}, {0.f, 0.f, 0.f}, {0.f, .75f, .0f}, DIFF }, /* Blue */
{ 10.f, {-30.f, 100.0f, 20.f}, {12.f, 12.f, 12.f}, {0.f, 0.f, 0.f}, DIFF } /* Lite */
};
#endif
#endif /* _SCENE_H */

60
scene_build_complex.pl Normal file
View File

@ -0,0 +1,60 @@
#!/usr/bin/perl
$maxDepth = 4.0;
sub PrintSphere {
my $depth = shift;
my $posx = shift;
my $posy = shift;
my $posz = shift;
my $rad = shift;
my $k = $depth / $maxDepth;
my $col1 = 0.75 * $k;
my $col2 = 0.75 * (1.0 - $k);
print "sphere $rad $posx $posy $posz 0 0 0 $col2 0 $col1 0\n";
}
sub HyperSphere {
my $depth = shift;
if ($depth <= $maxDepth) {
my $posx = shift;
my $posy = shift;
my $posz = shift;
my $rad = shift;
my $direction = shift;
PrintSphere($depth, $posx, $posy, $posz, $rad);
my $newRad = $rad / 2.0;
if ($direction != 0) {
HyperSphere($depth + 1.0, $posx - $rad - $newRad, $posy, $posz, $newRad, 1);
}
if ($direction != 1) {
HyperSphere($depth + 1.0, $posx + $rad + $newRad, $posy, $posz, $newRad, 0);
}
if ($direction != 2) {
HyperSphere($depth + 1.0, $posx, $posy - $rad - $newRad, $posz, $newRad, 3);
}
if ($direction != 3) {
HyperSphere($depth + 1.0, $posx, $posy + $rad + $newRad, $posz, $newRad, 2);
}
if ($direction != 4) {
HyperSphere($depth + 1.0, $posx, $posy, $posz - $rad - $newRad, $newRad, 5);
}
if ($direction != 5) {
HyperSphere($depth + 1.0, $posx, $posy, $posz + $rad + $newRad, $newRad, 4);
}
}
}
# Directions:
# 0 - from -x
# 1 - from +x
# 2 - from -y
# 3 - from +y
# 4 - from -z
# 5 - from +z
HyperSphere(0.0, 0.0, 0.0, 0.0, 15.0, 2);

5
scenes/caustic.scn Normal file
View File

@ -0,0 +1,5 @@
camera 20 80 300 0 40 0
size 3
sphere 1000 0 -1000 0 0 0 0 0.75 0.75 0.75 0
sphere 15 0 30 0 0 0 0 0.9 0.9 0.9 2
sphere 15 0 100 0 15 15 15 0 0 0 0

7
scenes/caustic3.scn Normal file
View File

@ -0,0 +1,7 @@
camera 20 100 300 0 25 0
size 5
sphere 1000 0 -1000 0 0 0 0 0.75 0.75 0.75 0
sphere 10 35 15 0 0 0 0 0.9 0 0 2
sphere 15 -35 20 0 0 0 0 0 0.9 0 2
sphere 20 0 25 -35 0 0 0 0 0 0.9 2
sphere 8 0 60 0 15 15 15 0 0 0 0

785
scenes/complex.scn Normal file
View File

@ -0,0 +1,785 @@
camera 20 80 150 0 15 0
size 783
sphere 8 50 80 90 25 25 25 0 0 0 0
sphere 10000 0 -10050 0 0 0 0 0.75 0.75 0.75 0
sphere 15 0 0 0 0 0 0 0.75 0 0 0
sphere 7.5 -22.5 0 0 0 0 0 0.5625 0 0.1875 0
sphere 3.75 -33.75 0 0 0 0 0 0.375 0 0.375 0
sphere 1.875 -39.375 0 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -42.1875 0 0 0 0 0 0 0 0.75 0
sphere 0.9375 -39.375 -2.8125 0 0 0 0 0 0 0.75 0
sphere 0.9375 -39.375 2.8125 0 0 0 0 0 0 0.75 0
sphere 0.9375 -39.375 0 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -39.375 0 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 -33.75 -5.625 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -36.5625 -5.625 0 0 0 0 0 0 0.75 0
sphere 0.9375 -30.9375 -5.625 0 0 0 0 0 0 0.75 0
sphere 0.9375 -33.75 -8.4375 0 0 0 0 0 0 0.75 0
sphere 0.9375 -33.75 -5.625 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -33.75 -5.625 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 -33.75 5.625 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -36.5625 5.625 0 0 0 0 0 0 0.75 0
sphere 0.9375 -30.9375 5.625 0 0 0 0 0 0 0.75 0
sphere 0.9375 -33.75 8.4375 0 0 0 0 0 0 0.75 0
sphere 0.9375 -33.75 5.625 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -33.75 5.625 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 -33.75 0 -5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -36.5625 0 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -30.9375 0 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -33.75 -2.8125 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -33.75 2.8125 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -33.75 0 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 -33.75 0 5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -36.5625 0 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -30.9375 0 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -33.75 -2.8125 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -33.75 2.8125 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -33.75 0 8.4375 0 0 0 0 0 0.75 0
sphere 3.75 -22.5 -11.25 0 0 0 0 0.375 0 0.375 0
sphere 1.875 -28.125 -11.25 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -30.9375 -11.25 0 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 -14.0625 0 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 -8.4375 0 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 -11.25 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 -11.25 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 -16.875 -11.25 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 -11.25 0 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 -14.0625 0 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 -8.4375 0 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 -11.25 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 -11.25 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 -22.5 -16.875 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -25.3125 -16.875 0 0 0 0 0 0 0.75 0
sphere 0.9375 -19.6875 -16.875 0 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -19.6875 0 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -16.875 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -16.875 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 -22.5 -11.25 -5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -25.3125 -11.25 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -19.6875 -11.25 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -14.0625 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -8.4375 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -11.25 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 -22.5 -11.25 5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -25.3125 -11.25 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -19.6875 -11.25 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -14.0625 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -8.4375 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -11.25 8.4375 0 0 0 0 0 0.75 0
sphere 3.75 -22.5 11.25 0 0 0 0 0.375 0 0.375 0
sphere 1.875 -28.125 11.25 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -30.9375 11.25 0 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 8.4375 0 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 14.0625 0 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 11.25 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 11.25 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 -16.875 11.25 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 11.25 0 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 8.4375 0 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 14.0625 0 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 11.25 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 11.25 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 -22.5 16.875 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -25.3125 16.875 0 0 0 0 0 0 0.75 0
sphere 0.9375 -19.6875 16.875 0 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 19.6875 0 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 16.875 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 16.875 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 -22.5 11.25 -5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -25.3125 11.25 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -19.6875 11.25 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 8.4375 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 14.0625 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 11.25 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 -22.5 11.25 5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -25.3125 11.25 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -19.6875 11.25 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 8.4375 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 14.0625 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 11.25 8.4375 0 0 0 0 0 0.75 0
sphere 3.75 -22.5 0 -11.25 0 0 0 0.375 0 0.375 0
sphere 1.875 -28.125 0 -11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -30.9375 0 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 -2.8125 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 2.8125 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 0 -14.0625 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 0 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 -16.875 0 -11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 0 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 -2.8125 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 2.8125 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 0 -14.0625 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 0 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 -22.5 -5.625 -11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -25.3125 -5.625 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -19.6875 -5.625 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -8.4375 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -5.625 -14.0625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -5.625 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 -22.5 5.625 -11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -25.3125 5.625 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -19.6875 5.625 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 8.4375 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 5.625 -14.0625 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 5.625 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 -22.5 0 -16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -25.3125 0 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -19.6875 0 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -2.8125 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 2.8125 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 0 -19.6875 0 0 0 0 0 0.75 0
sphere 3.75 -22.5 0 11.25 0 0 0 0.375 0 0.375 0
sphere 1.875 -28.125 0 11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -30.9375 0 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 -2.8125 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 2.8125 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 0 8.4375 0 0 0 0 0 0.75 0
sphere 0.9375 -28.125 0 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 -16.875 0 11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 0 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 -2.8125 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 2.8125 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 0 8.4375 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 0 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 -22.5 -5.625 11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -25.3125 -5.625 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -19.6875 -5.625 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -8.4375 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -5.625 8.4375 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -5.625 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 -22.5 5.625 11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -25.3125 5.625 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -19.6875 5.625 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 8.4375 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 5.625 8.4375 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 5.625 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 -22.5 0 16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -25.3125 0 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -19.6875 0 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 -2.8125 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 2.8125 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -22.5 0 19.6875 0 0 0 0 0 0.75 0
sphere 7.5 22.5 0 0 0 0 0 0.5625 0 0.1875 0
sphere 3.75 33.75 0 0 0 0 0 0.375 0 0.375 0
sphere 1.875 39.375 0 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 42.1875 0 0 0 0 0 0 0 0.75 0
sphere 0.9375 39.375 -2.8125 0 0 0 0 0 0 0.75 0
sphere 0.9375 39.375 2.8125 0 0 0 0 0 0 0.75 0
sphere 0.9375 39.375 0 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 39.375 0 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 33.75 -5.625 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 30.9375 -5.625 0 0 0 0 0 0 0.75 0
sphere 0.9375 36.5625 -5.625 0 0 0 0 0 0 0.75 0
sphere 0.9375 33.75 -8.4375 0 0 0 0 0 0 0.75 0
sphere 0.9375 33.75 -5.625 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 33.75 -5.625 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 33.75 5.625 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 30.9375 5.625 0 0 0 0 0 0 0.75 0
sphere 0.9375 36.5625 5.625 0 0 0 0 0 0 0.75 0
sphere 0.9375 33.75 8.4375 0 0 0 0 0 0 0.75 0
sphere 0.9375 33.75 5.625 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 33.75 5.625 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 33.75 0 -5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 30.9375 0 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 36.5625 0 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 33.75 -2.8125 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 33.75 2.8125 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 33.75 0 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 33.75 0 5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 30.9375 0 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 36.5625 0 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 33.75 -2.8125 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 33.75 2.8125 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 33.75 0 8.4375 0 0 0 0 0 0.75 0
sphere 3.75 22.5 -11.25 0 0 0 0 0.375 0 0.375 0
sphere 1.875 16.875 -11.25 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 14.0625 -11.25 0 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 -14.0625 0 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 -8.4375 0 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 -11.25 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 -11.25 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 28.125 -11.25 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 30.9375 -11.25 0 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 -14.0625 0 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 -8.4375 0 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 -11.25 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 -11.25 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 22.5 -16.875 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 -16.875 0 0 0 0 0 0 0.75 0
sphere 0.9375 25.3125 -16.875 0 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -19.6875 0 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -16.875 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -16.875 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 22.5 -11.25 -5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 -11.25 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 25.3125 -11.25 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -14.0625 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -8.4375 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -11.25 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 22.5 -11.25 5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 -11.25 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 25.3125 -11.25 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -14.0625 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -8.4375 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -11.25 8.4375 0 0 0 0 0 0.75 0
sphere 3.75 22.5 11.25 0 0 0 0 0.375 0 0.375 0
sphere 1.875 16.875 11.25 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 14.0625 11.25 0 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 8.4375 0 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 14.0625 0 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 11.25 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 11.25 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 28.125 11.25 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 30.9375 11.25 0 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 8.4375 0 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 14.0625 0 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 11.25 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 11.25 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 22.5 16.875 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 16.875 0 0 0 0 0 0 0.75 0
sphere 0.9375 25.3125 16.875 0 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 19.6875 0 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 16.875 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 16.875 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 22.5 11.25 -5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 11.25 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 25.3125 11.25 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 8.4375 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 14.0625 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 11.25 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 22.5 11.25 5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 11.25 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 25.3125 11.25 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 8.4375 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 14.0625 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 11.25 8.4375 0 0 0 0 0 0.75 0
sphere 3.75 22.5 0 -11.25 0 0 0 0.375 0 0.375 0
sphere 1.875 16.875 0 -11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 14.0625 0 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 -2.8125 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 2.8125 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 0 -14.0625 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 0 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 28.125 0 -11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 30.9375 0 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 -2.8125 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 2.8125 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 0 -14.0625 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 0 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 22.5 -5.625 -11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 -5.625 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 25.3125 -5.625 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -8.4375 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -5.625 -14.0625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -5.625 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 22.5 5.625 -11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 5.625 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 25.3125 5.625 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 8.4375 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 5.625 -14.0625 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 5.625 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 22.5 0 -16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 0 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 25.3125 0 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -2.8125 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 2.8125 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 0 -19.6875 0 0 0 0 0 0.75 0
sphere 3.75 22.5 0 11.25 0 0 0 0.375 0 0.375 0
sphere 1.875 16.875 0 11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 14.0625 0 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 -2.8125 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 2.8125 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 0 8.4375 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 0 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 28.125 0 11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 30.9375 0 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 -2.8125 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 2.8125 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 0 8.4375 0 0 0 0 0 0.75 0
sphere 0.9375 28.125 0 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 22.5 -5.625 11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 -5.625 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 25.3125 -5.625 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -8.4375 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -5.625 8.4375 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -5.625 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 22.5 5.625 11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 5.625 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 25.3125 5.625 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 8.4375 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 5.625 8.4375 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 5.625 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 22.5 0 16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 0 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 25.3125 0 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 -2.8125 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 2.8125 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 22.5 0 19.6875 0 0 0 0 0 0.75 0
sphere 7.5 0 22.5 0 0 0 0 0.5625 0 0.1875 0
sphere 3.75 -11.25 22.5 0 0 0 0 0.375 0 0.375 0
sphere 1.875 -16.875 22.5 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -19.6875 22.5 0 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 19.6875 0 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 25.3125 0 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 22.5 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 22.5 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 -11.25 16.875 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 16.875 0 0 0 0 0 0 0.75 0
sphere 0.9375 -8.4375 16.875 0 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 14.0625 0 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 16.875 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 16.875 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 -11.25 28.125 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 28.125 0 0 0 0 0 0 0.75 0
sphere 0.9375 -8.4375 28.125 0 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 30.9375 0 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 28.125 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 28.125 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 -11.25 22.5 -5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 22.5 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -8.4375 22.5 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 19.6875 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 25.3125 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 22.5 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 -11.25 22.5 5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 22.5 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -8.4375 22.5 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 19.6875 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 25.3125 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 22.5 8.4375 0 0 0 0 0 0.75 0
sphere 3.75 11.25 22.5 0 0 0 0 0.375 0 0.375 0
sphere 1.875 16.875 22.5 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 22.5 0 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 19.6875 0 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 25.3125 0 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 22.5 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 22.5 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 11.25 16.875 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 16.875 0 0 0 0 0 0 0.75 0
sphere 0.9375 14.0625 16.875 0 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 14.0625 0 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 16.875 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 16.875 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 11.25 28.125 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 28.125 0 0 0 0 0 0 0.75 0
sphere 0.9375 14.0625 28.125 0 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 30.9375 0 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 28.125 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 28.125 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 11.25 22.5 -5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 22.5 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 14.0625 22.5 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 19.6875 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 25.3125 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 22.5 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 11.25 22.5 5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 22.5 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 14.0625 22.5 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 19.6875 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 25.3125 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 22.5 8.4375 0 0 0 0 0 0.75 0
sphere 3.75 0 33.75 0 0 0 0 0.375 0 0.375 0
sphere 1.875 -5.625 33.75 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -8.4375 33.75 0 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 30.9375 0 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 36.5625 0 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 33.75 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 33.75 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 5.625 33.75 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 33.75 0 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 30.9375 0 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 36.5625 0 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 33.75 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 33.75 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 0 39.375 0 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 39.375 0 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 39.375 0 0 0 0 0 0 0.75 0
sphere 0.9375 0 42.1875 0 0 0 0 0 0 0.75 0
sphere 0.9375 0 39.375 -2.8125 0 0 0 0 0 0.75 0
sphere 0.9375 0 39.375 2.8125 0 0 0 0 0 0.75 0
sphere 1.875 0 33.75 -5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 33.75 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 33.75 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 0 30.9375 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 0 36.5625 -5.625 0 0 0 0 0 0.75 0
sphere 0.9375 0 33.75 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 0 33.75 5.625 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 33.75 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 33.75 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 0 30.9375 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 0 36.5625 5.625 0 0 0 0 0 0.75 0
sphere 0.9375 0 33.75 8.4375 0 0 0 0 0 0.75 0
sphere 3.75 0 22.5 -11.25 0 0 0 0.375 0 0.375 0
sphere 1.875 -5.625 22.5 -11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -8.4375 22.5 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 19.6875 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 25.3125 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 22.5 -14.0625 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 22.5 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 5.625 22.5 -11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 22.5 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 19.6875 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 25.3125 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 22.5 -14.0625 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 22.5 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 0 16.875 -11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 16.875 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 16.875 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 0 14.0625 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 0 16.875 -14.0625 0 0 0 0 0 0.75 0
sphere 0.9375 0 16.875 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 0 28.125 -11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 28.125 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 28.125 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 0 30.9375 -11.25 0 0 0 0 0 0.75 0
sphere 0.9375 0 28.125 -14.0625 0 0 0 0 0 0.75 0
sphere 0.9375 0 28.125 -8.4375 0 0 0 0 0 0.75 0
sphere 1.875 0 22.5 -16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 22.5 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 22.5 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 19.6875 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 25.3125 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 22.5 -19.6875 0 0 0 0 0 0.75 0
sphere 3.75 0 22.5 11.25 0 0 0 0.375 0 0.375 0
sphere 1.875 -5.625 22.5 11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -8.4375 22.5 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 19.6875 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 25.3125 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 22.5 8.4375 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 22.5 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 5.625 22.5 11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 22.5 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 19.6875 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 25.3125 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 22.5 8.4375 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 22.5 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 0 16.875 11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 16.875 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 16.875 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 0 14.0625 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 0 16.875 8.4375 0 0 0 0 0 0.75 0
sphere 0.9375 0 16.875 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 0 28.125 11.25 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 28.125 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 28.125 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 0 30.9375 11.25 0 0 0 0 0 0.75 0
sphere 0.9375 0 28.125 8.4375 0 0 0 0 0 0.75 0
sphere 0.9375 0 28.125 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 0 22.5 16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 22.5 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 22.5 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 19.6875 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 25.3125 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 22.5 19.6875 0 0 0 0 0 0.75 0
sphere 7.5 0 0 -22.5 0 0 0 0.5625 0 0.1875 0
sphere 3.75 -11.25 0 -22.5 0 0 0 0.375 0 0.375 0
sphere 1.875 -16.875 0 -22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -19.6875 0 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 -2.8125 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 2.8125 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 0 -25.3125 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 0 -19.6875 0 0 0 0 0 0.75 0
sphere 1.875 -11.25 -5.625 -22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 -5.625 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -8.4375 -5.625 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 -8.4375 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 -5.625 -25.3125 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 -5.625 -19.6875 0 0 0 0 0 0.75 0
sphere 1.875 -11.25 5.625 -22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 5.625 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -8.4375 5.625 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 8.4375 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 5.625 -25.3125 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 5.625 -19.6875 0 0 0 0 0 0.75 0
sphere 1.875 -11.25 0 -28.125 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 0 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 -8.4375 0 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 -2.8125 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 2.8125 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 0 -30.9375 0 0 0 0 0 0.75 0
sphere 1.875 -11.25 0 -16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 0 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -8.4375 0 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 -2.8125 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 2.8125 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 0 -14.0625 0 0 0 0 0 0.75 0
sphere 3.75 11.25 0 -22.5 0 0 0 0.375 0 0.375 0
sphere 1.875 16.875 0 -22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 0 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 -2.8125 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 2.8125 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 0 -25.3125 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 0 -19.6875 0 0 0 0 0 0.75 0
sphere 1.875 11.25 -5.625 -22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 -5.625 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 14.0625 -5.625 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 -8.4375 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 -5.625 -25.3125 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 -5.625 -19.6875 0 0 0 0 0 0.75 0
sphere 1.875 11.25 5.625 -22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 5.625 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 14.0625 5.625 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 8.4375 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 5.625 -25.3125 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 5.625 -19.6875 0 0 0 0 0 0.75 0
sphere 1.875 11.25 0 -28.125 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 0 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 14.0625 0 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 -2.8125 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 2.8125 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 0 -30.9375 0 0 0 0 0 0.75 0
sphere 1.875 11.25 0 -16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 0 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 14.0625 0 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 -2.8125 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 2.8125 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 0 -14.0625 0 0 0 0 0 0.75 0
sphere 3.75 0 -11.25 -22.5 0 0 0 0.375 0 0.375 0
sphere 1.875 -5.625 -11.25 -22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -8.4375 -11.25 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 -14.0625 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 -8.4375 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 -11.25 -25.3125 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 -11.25 -19.6875 0 0 0 0 0 0.75 0
sphere 1.875 5.625 -11.25 -22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 -11.25 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 -14.0625 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 -8.4375 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 -11.25 -25.3125 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 -11.25 -19.6875 0 0 0 0 0 0.75 0
sphere 1.875 0 -16.875 -22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 -16.875 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 -16.875 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 0 -19.6875 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 0 -16.875 -25.3125 0 0 0 0 0 0.75 0
sphere 0.9375 0 -16.875 -19.6875 0 0 0 0 0 0.75 0
sphere 1.875 0 -11.25 -28.125 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 -11.25 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 -11.25 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 0 -14.0625 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 0 -8.4375 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 0 -11.25 -30.9375 0 0 0 0 0 0.75 0
sphere 1.875 0 -11.25 -16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 -11.25 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 -11.25 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 -14.0625 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 -8.4375 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 -11.25 -14.0625 0 0 0 0 0 0.75 0
sphere 3.75 0 11.25 -22.5 0 0 0 0.375 0 0.375 0
sphere 1.875 -5.625 11.25 -22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -8.4375 11.25 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 8.4375 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 14.0625 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 11.25 -25.3125 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 11.25 -19.6875 0 0 0 0 0 0.75 0
sphere 1.875 5.625 11.25 -22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 11.25 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 8.4375 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 14.0625 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 11.25 -25.3125 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 11.25 -19.6875 0 0 0 0 0 0.75 0
sphere 1.875 0 16.875 -22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 16.875 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 16.875 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 0 19.6875 -22.5 0 0 0 0 0 0.75 0
sphere 0.9375 0 16.875 -25.3125 0 0 0 0 0 0.75 0
sphere 0.9375 0 16.875 -19.6875 0 0 0 0 0 0.75 0
sphere 1.875 0 11.25 -28.125 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 11.25 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 11.25 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 0 8.4375 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 0 14.0625 -28.125 0 0 0 0 0 0.75 0
sphere 0.9375 0 11.25 -30.9375 0 0 0 0 0 0.75 0
sphere 1.875 0 11.25 -16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 11.25 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 11.25 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 8.4375 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 14.0625 -16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 11.25 -14.0625 0 0 0 0 0 0.75 0
sphere 3.75 0 0 -33.75 0 0 0 0.375 0 0.375 0
sphere 1.875 -5.625 0 -33.75 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -8.4375 0 -33.75 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 -2.8125 -33.75 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 2.8125 -33.75 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 0 -36.5625 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 0 -30.9375 0 0 0 0 0 0.75 0
sphere 1.875 5.625 0 -33.75 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 0 -33.75 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 -2.8125 -33.75 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 2.8125 -33.75 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 0 -36.5625 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 0 -30.9375 0 0 0 0 0 0.75 0
sphere 1.875 0 -5.625 -33.75 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 -5.625 -33.75 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 -5.625 -33.75 0 0 0 0 0 0.75 0
sphere 0.9375 0 -8.4375 -33.75 0 0 0 0 0 0.75 0
sphere 0.9375 0 -5.625 -36.5625 0 0 0 0 0 0.75 0
sphere 0.9375 0 -5.625 -30.9375 0 0 0 0 0 0.75 0
sphere 1.875 0 5.625 -33.75 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 5.625 -33.75 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 5.625 -33.75 0 0 0 0 0 0.75 0
sphere 0.9375 0 8.4375 -33.75 0 0 0 0 0 0.75 0
sphere 0.9375 0 5.625 -36.5625 0 0 0 0 0 0.75 0
sphere 0.9375 0 5.625 -30.9375 0 0 0 0 0 0.75 0
sphere 1.875 0 0 -39.375 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 0 -39.375 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 0 -39.375 0 0 0 0 0 0.75 0
sphere 0.9375 0 -2.8125 -39.375 0 0 0 0 0 0.75 0
sphere 0.9375 0 2.8125 -39.375 0 0 0 0 0 0.75 0
sphere 0.9375 0 0 -42.1875 0 0 0 0 0 0.75 0
sphere 7.5 0 0 22.5 0 0 0 0.5625 0 0.1875 0
sphere 3.75 -11.25 0 22.5 0 0 0 0.375 0 0.375 0
sphere 1.875 -16.875 0 22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -19.6875 0 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 -2.8125 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 2.8125 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 0 19.6875 0 0 0 0 0 0.75 0
sphere 0.9375 -16.875 0 25.3125 0 0 0 0 0 0.75 0
sphere 1.875 -11.25 -5.625 22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 -5.625 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -8.4375 -5.625 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 -8.4375 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 -5.625 19.6875 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 -5.625 25.3125 0 0 0 0 0 0.75 0
sphere 1.875 -11.25 5.625 22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 5.625 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -8.4375 5.625 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 8.4375 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 5.625 19.6875 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 5.625 25.3125 0 0 0 0 0 0.75 0
sphere 1.875 -11.25 0 16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 0 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -8.4375 0 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 -2.8125 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 2.8125 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 0 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 -11.25 0 28.125 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -14.0625 0 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 -8.4375 0 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 -2.8125 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 2.8125 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 -11.25 0 30.9375 0 0 0 0 0 0.75 0
sphere 3.75 11.25 0 22.5 0 0 0 0.375 0 0.375 0
sphere 1.875 16.875 0 22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 19.6875 0 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 -2.8125 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 2.8125 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 0 19.6875 0 0 0 0 0 0.75 0
sphere 0.9375 16.875 0 25.3125 0 0 0 0 0 0.75 0
sphere 1.875 11.25 -5.625 22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 -5.625 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 14.0625 -5.625 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 -8.4375 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 -5.625 19.6875 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 -5.625 25.3125 0 0 0 0 0 0.75 0
sphere 1.875 11.25 5.625 22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 5.625 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 14.0625 5.625 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 8.4375 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 5.625 19.6875 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 5.625 25.3125 0 0 0 0 0 0.75 0
sphere 1.875 11.25 0 16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 0 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 14.0625 0 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 -2.8125 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 2.8125 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 0 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 11.25 0 28.125 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 0 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 14.0625 0 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 -2.8125 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 2.8125 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 11.25 0 30.9375 0 0 0 0 0 0.75 0
sphere 3.75 0 -11.25 22.5 0 0 0 0.375 0 0.375 0
sphere 1.875 -5.625 -11.25 22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -8.4375 -11.25 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 -14.0625 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 -8.4375 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 -11.25 19.6875 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 -11.25 25.3125 0 0 0 0 0 0.75 0
sphere 1.875 5.625 -11.25 22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 -11.25 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 -14.0625 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 -8.4375 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 -11.25 19.6875 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 -11.25 25.3125 0 0 0 0 0 0.75 0
sphere 1.875 0 -16.875 22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 -16.875 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 -16.875 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 0 -19.6875 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 0 -16.875 19.6875 0 0 0 0 0 0.75 0
sphere 0.9375 0 -16.875 25.3125 0 0 0 0 0 0.75 0
sphere 1.875 0 -11.25 16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 -11.25 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 -11.25 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 -14.0625 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 -8.4375 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 -11.25 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 0 -11.25 28.125 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 -11.25 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 -11.25 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 0 -14.0625 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 0 -8.4375 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 0 -11.25 30.9375 0 0 0 0 0 0.75 0
sphere 3.75 0 11.25 22.5 0 0 0 0.375 0 0.375 0
sphere 1.875 -5.625 11.25 22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -8.4375 11.25 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 8.4375 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 14.0625 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 11.25 19.6875 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 11.25 25.3125 0 0 0 0 0 0.75 0
sphere 1.875 5.625 11.25 22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 11.25 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 8.4375 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 14.0625 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 11.25 19.6875 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 11.25 25.3125 0 0 0 0 0 0.75 0
sphere 1.875 0 16.875 22.5 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 16.875 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 16.875 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 0 19.6875 22.5 0 0 0 0 0 0.75 0
sphere 0.9375 0 16.875 19.6875 0 0 0 0 0 0.75 0
sphere 0.9375 0 16.875 25.3125 0 0 0 0 0 0.75 0
sphere 1.875 0 11.25 16.875 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 11.25 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 11.25 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 8.4375 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 14.0625 16.875 0 0 0 0 0 0.75 0
sphere 0.9375 0 11.25 14.0625 0 0 0 0 0 0.75 0
sphere 1.875 0 11.25 28.125 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 11.25 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 11.25 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 0 8.4375 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 0 14.0625 28.125 0 0 0 0 0 0.75 0
sphere 0.9375 0 11.25 30.9375 0 0 0 0 0 0.75 0
sphere 3.75 0 0 33.75 0 0 0 0.375 0 0.375 0
sphere 1.875 -5.625 0 33.75 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -8.4375 0 33.75 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 -2.8125 33.75 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 2.8125 33.75 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 0 30.9375 0 0 0 0 0 0.75 0
sphere 0.9375 -5.625 0 36.5625 0 0 0 0 0 0.75 0
sphere 1.875 5.625 0 33.75 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 8.4375 0 33.75 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 -2.8125 33.75 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 2.8125 33.75 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 0 30.9375 0 0 0 0 0 0.75 0
sphere 0.9375 5.625 0 36.5625 0 0 0 0 0 0.75 0
sphere 1.875 0 -5.625 33.75 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 -5.625 33.75 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 -5.625 33.75 0 0 0 0 0 0.75 0
sphere 0.9375 0 -8.4375 33.75 0 0 0 0 0 0.75 0
sphere 0.9375 0 -5.625 30.9375 0 0 0 0 0 0.75 0
sphere 0.9375 0 -5.625 36.5625 0 0 0 0 0 0.75 0
sphere 1.875 0 5.625 33.75 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 5.625 33.75 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 5.625 33.75 0 0 0 0 0 0.75 0
sphere 0.9375 0 8.4375 33.75 0 0 0 0 0 0.75 0
sphere 0.9375 0 5.625 30.9375 0 0 0 0 0 0.75 0
sphere 0.9375 0 5.625 36.5625 0 0 0 0 0 0.75 0
sphere 1.875 0 0 39.375 0 0 0 0.1875 0 0.5625 0
sphere 0.9375 -2.8125 0 39.375 0 0 0 0 0 0.75 0
sphere 0.9375 2.8125 0 39.375 0 0 0 0 0 0.75 0
sphere 0.9375 0 -2.8125 39.375 0 0 0 0 0 0.75 0
sphere 0.9375 0 2.8125 39.375 0 0 0 0 0 0.75 0
sphere 0.9375 0 0 42.1875 0 0 0 0 0 0.75 0

11
scenes/cornell.scn Normal file
View File

@ -0,0 +1,11 @@
camera 50 45 205.6 50 44.957388 204.6
size 9
sphere 10000 10001 40.8 81.6 0 0 0 0.75 .25 0.25 0
sphere 10000 -9901 40.8 81.6 0 0 0 0.25 .25 0.75 0
sphere 10000 50 40.8 10000 0 0 0 0.75 .75 0.75 0
sphere 10000 50 40.8 -9730 0 0 0 0 0 0 0
sphere 10000 50 10000 81.6 0 0 0 0.75 .75 0.75 0
sphere 10000 50 -9918.4 81.6 0 0 0 0.75 .75 0.75 0
sphere 16.5 27 16.5 47 0 0 0 0.9 0.9 0.9 1
sphere 16.5 73 16.5 78 0 0 0 0.9 0.9 0.9 2
sphere 7 50 66.6 81.6 12 12 12 0 0 0 0

11
scenes/cornell_large.scn Normal file
View File

@ -0,0 +1,11 @@
camera 50 45 295.6 50 44.957388 294.6
size 9
sphere 10000 10001 40.8 81.6 0 0 0 0.75 .25 0.25 0
sphere 10000 -9801 40.8 81.6 0 0 0 0.25 .25 0.75 0
sphere 10000 50 40.8 10000 0 0 0 0.75 .75 0.75 0
sphere 10000 50 40.8 -9530 0 0 0 0.75 .75 0.75 0
sphere 10000 50 10000 81.6 0 0 0 0.75 .75 0.75 0
sphere 10000 50 -9818.4 81.6 0 0 0 0.75 .75 0.75 0
sphere 16.5 27 16.5 47 0 0 0 0.9 0.9 0.9 1
sphere 16.5 73 16.5 78 0 0 0 0.9 0.9 0.9 2
sphere 7 50 66.6 81.6 12 12 12 0 0 0 0

7
scenes/simple.scn Normal file
View File

@ -0,0 +1,7 @@
camera 20 80 300 0 15 0
size 5
sphere 1000 0 -1000 0 0 0 0 0.75 0.75 0.75 0
sphere 10 35 10 0 0 0 0 0.75 0 0 0
sphere 15 -35 15 0 0 0 0 0 0.75 0 0
sphere 20 0 20 -35 0 0 0 0 0 0.75 0
sphere 8 0 60 0 15 15 15 0 0 0 0

53
simplernd.h Normal file
View File

@ -0,0 +1,53 @@
/*
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _SIMPLERND_H
#define _SIMPLERND_H
/*
* A Simple Random number generator
* from http://en.wikipedia.org/wiki/Random_number_generator
*/
#ifndef SMALLPT_GPU
static float GetRandom(unsigned int *seed0, unsigned int *seed1) {
*seed0 = 36969 * ((*seed0) & 65535) + ((*seed0) >> 16);
*seed1 = 18000 * ((*seed1) & 65535) + ((*seed1) >> 16);
unsigned int ires = ((*seed0) << 16) + (*seed1);
/* Convert to float */
union {
float f;
unsigned int ui;
} res;
res.ui = (ires & 0x007fffff) | 0x40000000;
return (res.f - 2.f) / 2.f;
}
#endif
#endif /* _SIMPLERND_H */

BIN
smallptCPU Normal file

Binary file not shown.

175
smallptCPU.c Normal file
View File

@ -0,0 +1,175 @@
/*
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* Based on smallpt, a Path Tracer by Kevin Beason, 2008
* Modified by David Bucciarelli to show the output via OpenGL/GLUT, ported
* to C, work with float, fixed RR, ported to OpenCL, etc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <math.h>
#include "camera.h"
#include "scene.h"
#include "displayfunc.h"
int workGroupSize = 1;
static Vec *colors;
static unsigned int *seeds;
Camera camera;
static int currentSample = 0;
Sphere *spheres;
unsigned int sphereCount;
void FreeBuffers() {
free(seeds);
free(colors);
free(pixels);
}
void AllocateBuffers() {
const int pixelCount = height * width ;
int i;
colors = malloc(sizeof(Vec[pixelCount]));
seeds = malloc(sizeof(unsigned int[pixelCount * 2]));
for (i = 0; i < pixelCount * 2; i++) {
seeds[i] = rand();
if (seeds[i] < 2)
seeds[i] = 2;
}
pixels = malloc(sizeof(unsigned int[pixelCount]));
}
void UpdateRendering(void) {
double startTime = WallClockTime();
const float invWidth = 1.f / width;
const float invHeight = 1.f / height;
int x, y;
for (y = 0; y < height; y++) { /* Loop over image rows */
for (x = 0; x < width; x++) { /* Loop cols */
const int i = (height - y - 1) * width + x;
const int i2 = 2 * i;
const float r1 = GetRandom(&seeds[i2], &seeds[i2 + 1]) - .5f;
const float r2 = GetRandom(&seeds[i2], &seeds[i2 + 1]) - .5f;
const float kcx = (x + r1) * invWidth - .5f;
const float kcy = (y + r2) * invHeight - .5f;
Vec rdir;
vinit(rdir,
camera.x.x * kcx + camera.y.x * kcy + camera.dir.x,
camera.x.y * kcx + camera.y.y * kcy + camera.dir.y,
camera.x.z * kcx + camera.y.z * kcy + camera.dir.z);
Vec rorig;
vsmul(rorig, 0.1f, rdir);
vadd(rorig, rorig, camera.orig)
vnorm(rdir);
const Ray ray = {rorig, rdir};
Vec r;
RadiancePathTracing(spheres, sphereCount, &ray,
&seeds[i2], &seeds[i2 + 1], &r);
if (currentSample == 0)
colors[i] = r;
else {
const float k1 = currentSample;
const float k2 = 1.f / (k1 + 1.f);
colors[i].x = (colors[i].x * k1 + r.x) * k2;
colors[i].y = (colors[i].y * k1 + r.y) * k2;
colors[i].z = (colors[i].z * k1 + r.z) * k2;
}
pixels[y * width + x] = toInt(colors[i].x) |
(toInt(colors[i].y) << 8) |
(toInt(colors[i].z) << 16);
}
}
const float elapsedTime = WallClockTime() - startTime;
const float sampleSec = height * width / elapsedTime;
sprintf(captionBuffer, "Rendering time %.3f sec (pass %d) Sample/sec %.1fK\n",
elapsedTime, currentSample, sampleSec / 1000.f);
currentSample++;
}
void ReInitScene() {
currentSample = 0;
}
void ReInit(const int reallocBuffers) {
// Check if I have to reallocate buffers
if (reallocBuffers) {
FreeBuffers();
AllocateBuffers();
}
UpdateCamera();
currentSample = 0;
UpdateRendering();
}
int main(int argc, char *argv[]) {
amiSmallptCPU = 1;
fprintf(stderr, "Usage: %s\n", argv[0]);
fprintf(stderr, "Usage: %s <window width> <window height> <scene file>\n", argv[0]);
if (argc == 4) {
width = atoi(argv[1]);
height = atoi(argv[2]);
ReadScene(argv[3]);
} else if (argc == 1) {
spheres = CornellSpheres;
sphereCount = sizeof(CornellSpheres) / sizeof(Sphere);
vinit(camera.orig, 50.f, 45.f, 205.6f);
vinit(camera.target, 50.f, 45 - 0.042612f, 204.6);
} else
exit(-1);
UpdateCamera();
/*------------------------------------------------------------------------*/
AllocateBuffers();
/*------------------------------------------------------------------------*/
InitGlut(argc, argv, "SmallPT CPU V1.6 (Written by David Bucciarelli)");
glutMainLoop( );
return 0;
}

BIN
smallptGPU Normal file

Binary file not shown.

862
smallptGPU.c Normal file
View File

@ -0,0 +1,862 @@
/*
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*
* Based on smallpt, a Path Tracer by Kevin Beason, 2008
* Modified by David Bucciarelli to show the output via OpenGL/GLUT, ported
* to C, work with float, fixed RR, ported to OpenCL, etc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <math.h>
// Jens's patch for MacOS
#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif
#include "camera.h"
#include "scene.h"
#include "displayfunc.h"
/* Options */
static int useGPU = 1;
static int forceWorkSize = 0;
/* OpenCL variables */
static cl_context context;
static cl_mem colorBuffer;
static cl_mem pixelBuffer;
static cl_mem seedBuffer;
static cl_mem sphereBuffer;
static cl_mem cameraBuffer;
static cl_command_queue commandQueue;
static cl_program program;
static cl_kernel kernel;
static unsigned int workGroupSize = 1;
static char *kernelFileName = "rendering_kernel.cl";
static Vec *colors;
static unsigned int *seeds;
Camera camera;
static int currentSample = 0;
Sphere *spheres;
unsigned int sphereCount;
static void FreeBuffers() {
cl_int status = clReleaseMemObject(colorBuffer);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to release OpenCL color buffer: %d\n", status);
exit(-1);
}
status = clReleaseMemObject(pixelBuffer);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to release OpenCL pixel buffer: %d\n", status);
exit(-1);
}
status = clReleaseMemObject(seedBuffer);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to release OpenCL seed buffer: %d\n", status);
exit(-1);
}
free(seeds);
free(colors);
free(pixels);
}
static void AllocateBuffers() {
const int pixelCount = width * height;
int i;
colors = (Vec *)malloc(sizeof(Vec) * pixelCount);
seeds = (unsigned int *)malloc(sizeof(unsigned int) * pixelCount * 2);
for (i = 0; i < pixelCount * 2; i++) {
seeds[i] = rand();
if (seeds[i] < 2)
seeds[i] = 2;
}
pixels = (unsigned int *)malloc(sizeof(unsigned int) * pixelCount);
// Test colors
for(i = 0; i < pixelCount; ++i)
pixels[i] = i;
cl_int status;
cl_uint sizeBytes = sizeof(Vec) * width * height;
colorBuffer = clCreateBuffer(
context,
CL_MEM_READ_WRITE,
sizeBytes,
NULL,
&status);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to create OpenCL output buffer: %d\n", status);
exit(-1);
}
sizeBytes = sizeof(unsigned int) * width * height;
pixelBuffer = clCreateBuffer(
context,
CL_MEM_WRITE_ONLY,
sizeBytes,
NULL,
&status);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to create OpenCL pixel buffer: %d\n", status);
exit(-1);
}
sizeBytes = sizeof(unsigned int) * width * height * 2;
seedBuffer = clCreateBuffer(
context,
CL_MEM_READ_WRITE,
sizeBytes,
NULL,
&status);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to create OpenCL seed buffer: %d\n", status);
exit(-1);
}
status = clEnqueueWriteBuffer(
commandQueue,
seedBuffer,
CL_TRUE,
0,
sizeBytes,
seeds,
0,
NULL,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to write the OpenCL seeds buffer: %d\n", status);
exit(-1);
}
}
static char *ReadSources(const char *fileName) {
FILE *file = fopen(fileName, "r");
if (!file) {
fprintf(stderr, "Failed to open file '%s'\n", fileName);
exit(-1);
}
if (fseek(file, 0, SEEK_END)) {
fprintf(stderr, "Failed to seek file '%s'\n", fileName);
exit(-1);
}
long size = ftell(file);
if (size == 0) {
fprintf(stderr, "Failed to check position on file '%s'\n", fileName);
exit(-1);
}
rewind(file);
char *src = (char *)malloc(sizeof(char) * size + 1);
if (!src) {
fprintf(stderr, "Failed to allocate memory for file '%s'\n", fileName);
exit(-1);
}
fprintf(stderr, "Reading file '%s' (size %ld bytes)\n", fileName, size);
size_t res = fread(src, 1, sizeof(char) * size, file);
if (res != sizeof(char) * size) {
fprintf(stderr, "Failed to read file '%s' (read %ld)\n", fileName, res);
exit(-1);
}
src[size] = '\0'; /* NULL terminated */
fclose(file);
return src;
}
static void SetUpOpenCL() {
cl_device_type dType;
if (useGPU)
dType = CL_DEVICE_TYPE_GPU;
else
dType = CL_DEVICE_TYPE_CPU;
// Select the platform
cl_uint numPlatforms;
cl_platform_id platform = NULL;
cl_int status = clGetPlatformIDs(0, NULL, &numPlatforms);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL platforms\n");
exit(-1);
}
if (numPlatforms > 0) {
cl_platform_id *platforms = (cl_platform_id *)malloc(sizeof(cl_platform_id) * numPlatforms);
status = clGetPlatformIDs(numPlatforms, platforms, NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL platform IDs\n");
exit(-1);
}
unsigned int i;
for (i = 0; i < numPlatforms; ++i) {
char pbuf[100];
status = clGetPlatformInfo(platforms[i],
CL_PLATFORM_VENDOR,
sizeof(pbuf),
pbuf,
NULL);
status = clGetPlatformIDs(numPlatforms, platforms, NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL platform IDs\n");
exit(-1);
}
fprintf(stderr, "OpenCL Platform %d: %s\n", i, pbuf);
}
platform = platforms[0];
free(platforms);
}
// Select the device
cl_device_id devices[32];
cl_uint deviceCount;
status = clGetDeviceIDs(platform, CL_DEVICE_TYPE_ALL, 32, devices, &deviceCount);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL device IDs\n");
exit(-1);
}
int deviceFound = 0;
cl_device_id selectedDevice;
unsigned int i;
for (i = 0; i < deviceCount; ++i) {
cl_device_type type = 0;
status = clGetDeviceInfo(devices[i],
CL_DEVICE_TYPE,
sizeof(cl_device_type),
&type,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL device info: %d\n", status);
exit(-1);
}
char *stype;
switch (type) {
case CL_DEVICE_TYPE_ALL:
stype = "TYPE_ALL";
break;
case CL_DEVICE_TYPE_DEFAULT:
stype = "TYPE_DEFAULT";
break;
case CL_DEVICE_TYPE_CPU:
stype = "TYPE_CPU";
if (!useGPU && !deviceFound) {
selectedDevice = devices[i];
deviceFound = 1;
}
break;
case CL_DEVICE_TYPE_GPU:
stype = "TYPE_GPU";
if (useGPU && !deviceFound) {
selectedDevice = devices[i];
deviceFound = 1;
}
break;
default:
stype = "TYPE_UNKNOWN";
break;
}
fprintf(stderr, "OpenCL Device %d: Type = %s\n", i, stype);
char buf[256];
status = clGetDeviceInfo(devices[i],
CL_DEVICE_NAME,
sizeof(char[256]),
&buf,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL device info: %d\n", status);
exit(-1);
}
fprintf(stderr, "OpenCL Device %d: Name = %s\n", i, buf);
cl_uint units = 0;
status = clGetDeviceInfo(devices[i],
CL_DEVICE_MAX_COMPUTE_UNITS,
sizeof(cl_uint),
&units,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL device info: %d\n", status);
exit(-1);
}
fprintf(stderr, "OpenCL Device %d: Compute units = %u\n", i, units);
size_t gsize = 0;
status = clGetDeviceInfo(devices[i],
CL_DEVICE_MAX_WORK_GROUP_SIZE,
sizeof(size_t),
&gsize,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL device info: %d\n", status);
exit(-1);
}
fprintf(stderr, "OpenCL Device %d: Max. work group size = %d\n", i, (unsigned int)gsize);
}
if (!deviceFound) {
fprintf(stderr, "Unable to select an appropriate device\n");
exit(-1);
}
// Create the context
cl_context_properties cps[3] = {
CL_CONTEXT_PLATFORM,
(cl_context_properties) platform,
0
};
cl_context_properties *cprops = (NULL == platform) ? NULL : cps;
context = clCreateContext(
cprops,
1,
&selectedDevice,
NULL,
NULL,
&status);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to open OpenCL context\n");
exit(-1);
}
/* Get the device list data */
size_t deviceListSize;
status = clGetContextInfo(
context,
CL_CONTEXT_DEVICES,
32,
devices,
&deviceListSize);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL context info: %d\n", status);
exit(-1);
}
/* Print devices list */
for (i = 0; i < deviceListSize / sizeof(cl_device_id); ++i) {
cl_device_type type = 0;
status = clGetDeviceInfo(devices[i],
CL_DEVICE_TYPE,
sizeof(cl_device_type),
&type,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL device info: %d\n", status);
exit(-1);
}
char *stype;
switch (type) {
case CL_DEVICE_TYPE_ALL:
stype = "TYPE_ALL";
break;
case CL_DEVICE_TYPE_DEFAULT:
stype = "TYPE_DEFAULT";
break;
case CL_DEVICE_TYPE_CPU:
stype = "TYPE_CPU";
break;
case CL_DEVICE_TYPE_GPU:
stype = "TYPE_GPU";
break;
default:
stype = "TYPE_UNKNOWN";
break;
}
fprintf(stderr, "[SELECTED] OpenCL Device %d: Type = %s\n", i, stype);
char buf[256];
status = clGetDeviceInfo(devices[i],
CL_DEVICE_NAME,
sizeof(char[256]),
&buf,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL device info: %d\n", status);
exit(-1);
}
fprintf(stderr, "[SELECTED] OpenCL Device %d: Name = %s\n", i, buf);
cl_uint units = 0;
status = clGetDeviceInfo(devices[i],
CL_DEVICE_MAX_COMPUTE_UNITS,
sizeof(cl_uint),
&units,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL device info: %d\n", status);
exit(-1);
}
fprintf(stderr, "[SELECTED] OpenCL Device %d: Compute units = %u\n", i, units);
size_t gsize = 0;
status = clGetDeviceInfo(devices[i],
CL_DEVICE_MAX_WORK_GROUP_SIZE,
sizeof(size_t),
&gsize,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL device info: %d\n", status);
exit(-1);
}
fprintf(stderr, "[SELECTED] OpenCL Device %d: Max. work group size = %d\n", i, (unsigned int)gsize);
}
cl_command_queue_properties prop = 0;
commandQueue = clCreateCommandQueue(
context,
devices[0],
prop,
&status);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to create OpenCL command queue: %d\n", status);
exit(-1);
}
/*------------------------------------------------------------------------*/
sphereBuffer = clCreateBuffer(
context,
#ifdef __APPLE__
CL_MEM_READ_WRITE, // NOTE: not READ_ONLY because of Apple's OpenCL bug
#else
CL_MEM_READ_ONLY,
#endif
sizeof(Sphere) * sphereCount,
NULL,
&status);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to create OpenCL scene buffer: %d\n", status);
exit(-1);
}
status = clEnqueueWriteBuffer(
commandQueue,
sphereBuffer,
CL_TRUE,
0,
sizeof(Sphere) * sphereCount,
spheres,
0,
NULL,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to write the OpenCL scene buffer: %d\n", status);
exit(-1);
}
cameraBuffer = clCreateBuffer(
context,
#ifdef __APPLE__
CL_MEM_READ_WRITE, // NOTE: not READ_ONLY because of Apple's OpenCL bug
#else
CL_MEM_READ_ONLY,
#endif
sizeof(Camera),
NULL,
&status);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to create OpenCL camera buffer: %d\n", status);
exit(-1);
}
status = clEnqueueWriteBuffer(
commandQueue,
cameraBuffer,
CL_TRUE,
0,
sizeof(Camera),
&camera,
0,
NULL,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to write the OpenCL camera buffer: %d\n", status);
exit(-1);
}
AllocateBuffers();
/*------------------------------------------------------------------------*/
/* Create the kernel program */
const char *sources = ReadSources(kernelFileName);
program = clCreateProgramWithSource(
context,
1,
&sources,
NULL,
&status);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to open OpenCL kernel sources: %d\n", status);
exit(-1);
}
#ifdef __APPLE__
status = clBuildProgram(program, 1, devices, "-I. -D__APPLE__", NULL, NULL);
#else
status = clBuildProgram(program, 1, devices, "-I. ", NULL, NULL);
#endif
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to build OpenCL kernel: %d\n", status);
size_t retValSize;
status = clGetProgramBuildInfo(
program,
devices[0],
CL_PROGRAM_BUILD_LOG,
0,
NULL,
&retValSize);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL kernel info size: %d\n", status);
exit(-1);
}
char *buildLog = (char *)malloc(retValSize + 1);
status = clGetProgramBuildInfo(
program,
devices[0],
CL_PROGRAM_BUILD_LOG,
retValSize,
buildLog,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL kernel info: %d\n", status);
exit(-1);
}
buildLog[retValSize] = '\0';
fprintf(stderr, "OpenCL Programm Build Log: %s\n", buildLog);
exit(-1);
}
kernel = clCreateKernel(program, "RadianceGPU", &status);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to create OpenCL kernel: %d\n", status);
exit(-1);
}
// LordCRC's patch for better workGroupSize
size_t gsize = 0;
status = clGetKernelWorkGroupInfo(kernel,
devices[0],
CL_KERNEL_WORK_GROUP_SIZE,
sizeof(size_t),
&gsize,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to get OpenCL kernel work group size info: %d\n", status);
exit(-1);
}
workGroupSize = (unsigned int) gsize;
fprintf(stderr, "OpenCL Device 0: kernel work group size = %d\n", workGroupSize);
if (forceWorkSize > 0) {
fprintf(stderr, "OpenCL Device 0: forced kernel work group size = %d\n", forceWorkSize);
workGroupSize = forceWorkSize;
}
}
static void ExecuteKernel() {
/* Enqueue a kernel run call */
size_t globalThreads[1];
globalThreads[0] = width * height;
if (globalThreads[0] % workGroupSize != 0)
globalThreads[0] = (globalThreads[0] / workGroupSize + 1) * workGroupSize;
size_t localThreads[1];
localThreads[0] = workGroupSize;
cl_int status = clEnqueueNDRangeKernel(
commandQueue,
kernel,
1,
NULL,
globalThreads,
localThreads,
0,
NULL,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to enqueue OpenCL work: %d\n", status);
exit(-1);
}
}
void UpdateRendering() {
double startTime = WallClockTime();
int startSampleCount = currentSample;
/* Set kernel arguments */
cl_int status = clSetKernelArg(
kernel,
0,
sizeof(cl_mem),
(void *)&colorBuffer);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to set OpenCL arg. #1: %d\n", status);
exit(-1);
}
status = clSetKernelArg(
kernel,
1,
sizeof(cl_mem),
(void *)&seedBuffer);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to set OpenCL arg. #2: %d\n", status);
exit(-1);
}
status = clSetKernelArg(
kernel,
2,
sizeof(cl_mem),
(void *)&sphereBuffer);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to set OpenCL arg. #3: %d\n", status);
exit(-1);
}
status = clSetKernelArg(
kernel,
3,
sizeof(cl_mem),
(void *)&cameraBuffer);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to set OpenCL arg. #4: %d\n", status);
exit(-1);
}
status = clSetKernelArg(
kernel,
4,
sizeof(unsigned int),
(void *)&sphereCount);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to set OpenCL arg. #5: %d\n", status);
exit(-1);
}
status = clSetKernelArg(
kernel,
5,
sizeof(int),
(void *)&width);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to set OpenCL arg. #6: %d\n", status);
exit(-1);
}
status = clSetKernelArg(
kernel,
6,
sizeof(int),
(void *)&height);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to set OpenCL arg. #7: %d\n", status);
exit(-1);
}
status = clSetKernelArg(
kernel,
7,
sizeof(int),
(void *)&currentSample);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to set OpenCL arg. #8: %d\n", status);
exit(-1);
}
status = clSetKernelArg(
kernel,
8,
sizeof(cl_mem),
(void *)&pixelBuffer);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to set OpenCL arg. #9: %d\n", status);
exit(-1);
}
//--------------------------------------------------------------------------
if (currentSample < 20) {
ExecuteKernel();
currentSample++;
} else {
/* After first 20 samples, continue to execute kernels for more and more time */
const float k = min(currentSample - 20, 100) / 100.f;
const float tresholdTime = 0.5f * k;
for (;;) {
ExecuteKernel();
clFinish(commandQueue);
currentSample++;
const float elapsedTime = WallClockTime() - startTime;
if (elapsedTime > tresholdTime)
break;
}
}
//--------------------------------------------------------------------------
/* Enqueue readBuffer */
status = clEnqueueReadBuffer(
commandQueue,
pixelBuffer,
CL_TRUE,
0,
width * height * sizeof(unsigned int),
pixels,
0,
NULL,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to read the OpenCL pixel buffer: %d\n", status);
exit(-1);
}
/*------------------------------------------------------------------------*/
const double elapsedTime = WallClockTime() - startTime;
const int samples = currentSample - startSampleCount;
const double sampleSec = samples * height * width / elapsedTime;
sprintf(captionBuffer, "Rendering time %.3f sec (pass %d) Sample/sec %.1fK\n",
elapsedTime, currentSample, sampleSec / 1000.f);
}
void ReInitScene() {
currentSample = 0;
// Redownload the scene
cl_int status = clEnqueueWriteBuffer(
commandQueue,
sphereBuffer,
CL_TRUE,
0,
sizeof(Sphere) * sphereCount,
spheres,
0,
NULL,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to write the OpenCL scene buffer: %d\n", status);
exit(-1);
}
}
void ReInit(const int reallocBuffers) {
// Check if I have to reallocate buffers
if (reallocBuffers) {
FreeBuffers();
UpdateCamera();
AllocateBuffers();
} else
UpdateCamera();
cl_int status = clEnqueueWriteBuffer(
commandQueue,
cameraBuffer,
CL_TRUE,
0,
sizeof(Camera),
&camera,
0,
NULL,
NULL);
if (status != CL_SUCCESS) {
fprintf(stderr, "Failed to write the OpenCL camera buffer: %d\n", status);
exit(-1);
}
currentSample = 0;
}
int main(int argc, char *argv[]) {
amiSmallptCPU = 0;
fprintf(stderr, "Usage: %s\n", argv[0]);
fprintf(stderr, "Usage: %s <use CPU/GPU device (0=CPU or 1=GPU)> <workgroup size (0=default value or anything > 0 and power of 2)> <kernel file name> <window width> <window height> <scene file>\n", argv[0]);
if (argc == 7) {
useGPU = atoi(argv[1]);
forceWorkSize = atoi(argv[2]);
kernelFileName = argv[3];
width = atoi(argv[4]);
height = atoi(argv[5]);
ReadScene(argv[6]);
} else if (argc == 1) {
spheres = CornellSpheres;
sphereCount = sizeof(CornellSpheres) / sizeof(Sphere);
vinit(camera.orig, 50.f, 45.f, 205.6f);
vinit(camera.target, 50.f, 45 - 0.042612f, 204.6);
} else
exit(-1);
UpdateCamera();
/*------------------------------------------------------------------------*/
SetUpOpenCL();
/*------------------------------------------------------------------------*/
InitGlut(argc, argv, "SmallPT GPU V1.6 (Written by David Bucciarelli)");
glutMainLoop();
return 0;
}

66
vec.h Normal file
View File

@ -0,0 +1,66 @@
/*
Copyright (c) 2009 David Bucciarelli (davibu@interfree.it)
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef _VEC_H
#define _VEC_H
typedef struct {
float x, y, z; // position, also color (r,g,b)
} Vec;
#define vinit(v, a, b, c) { (v).x = a; (v).y = b; (v).z = c; }
#define vassign(a, b) vinit(a, (b).x, (b).y, (b).z)
#define vclr(v) vinit(v, 0.f, 0.f, 0.f)
#define vadd(v, a, b) vinit(v, (a).x + (b).x, (a).y + (b).y, (a).z + (b).z)
#define vsub(v, a, b) vinit(v, (a).x - (b).x, (a).y - (b).y, (a).z - (b).z)
#define vsadd(v, a, b) { float k = (a); vinit(v, (b).x + k, (b).y + k, (b).z + k) }
#define vssub(v, a, b) { float k = (a); vinit(v, (b).x - k, (b).y - k, (b).z - k) }
#define vmul(v, a, b) vinit(v, (a).x * (b).x, (a).y * (b).y, (a).z * (b).z)
#define vsmul(v, a, b) { float k = (a); vinit(v, k * (b).x, k * (b).y, k * (b).z) }
#define vdot(a, b) ((a).x * (b).x + (a).y * (b).y + (a).z * (b).z)
#define vnorm(v) { float l = 1.f / sqrt(vdot(v, v)); vsmul(v, l, v); }
#define vxcross(v, a, b) vinit(v, (a).y * (b).z - (a).z * (b).y, (a).z * (b).x - (a).x * (b).z, (a).x * (b).y - (a).y * (b).x)
#define vfilter(v) ((v).x > (v).y && (v).x > (v).z ? (v).x : (v).y > (v).z ? (v).y : (v).z)
#define viszero(v) (((v).x == 0.f) && ((v).x == 0.f) && ((v).z == 0.f))
#ifndef GPU_KERNEL
#define clamp(x, a, b) ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
#define max(x, y) ( (x) > (y) ? (x) : (y))
#define min(x, y) ( (x) < (y) ? (x) : (y))
#define sign(x) ((x) > 0 ? 1 : -1)
#endif
#define toInt(x) ((int)(pow(clamp(x, 0.f, 1.f), 1.f / 2.2f) * 255.f + .5f))
// Rendering flags
#define RFLAGS_DISABLE_DIFFUSE_PATH 1
// NOTE: workaround for an Apple OpenCL compiler bug
#ifdef __APPLE__
#define OCL_CONSTANT_BUFFER __global
#else
#define OCL_CONSTANT_BUFFER __constant
#endif
#endif /* _VEC_H */