I’m trying to understand how all this works. A quick and dirty java version should be something like :
The octree :
public class Octree
{
protected OctreeCell root;
public float sx;
public float sy;
public float sz;
public float x;
public float y;
public float z;
public int depth;
public Octree()
{
root = new OctreeCell();
x = 0;
y = 0;
z = 0;
sx = 1024;
sy = 1024;
sz = 128;
depth = 9;
}
public void set(float x,float y,float z,byte r,byte g,byte b)
{
root.set(depth,x,y,z,r,g,b);
}
public void validate()
{
root.validate(depth);
}
public OctreeCell getRoot()
{
return root;
}
}
The octree cell :
public class OctreeCell
{
protected OctreeCell childs[][][];
protected byte red,green,blue;
public OctreeCell()
{
childs = new OctreeCell[2][2][2];
}
public OctreeCell get(int iteration,float x,float y,float z)
{
if (iteration == 0)
{
return this;
}
int ix = 0; if (x>=0.5) { ix =1; }
int iy = 0; if (y>=0.5) { iy =1; }
int iz = 0; if (z>=0.5) { iz =1; }
if (childs[ix][iy][iz] == null) { return null; }
return childs[ix][iy][iz].get(iteration-1, x*2-ix, y*2-iy, z*2-iz);
}
public void set(int iteration,float x,float y,float z,byte r,byte g,byte b)
{
if (iteration == 0)
{
red = r;
green = g;
blue = b;
return;
}
int ix = 0; if (x>=0.5) { ix =1; }
int iy = 0; if (y>=0.5) { iy =1; }
int iz = 0; if (z>=0.5) { iz =1; }
if (childs[ix][iy][iz] == null) { childs[ix][iy][iz] = new OctreeCell(); }
childs[ix][iy][iz].set(iteration-1, x*2-ix, y*2-iy, z*2-iz,r,g,b);
}
public int getColor()
{
return (red&0xFF)+((green&0xFF)<<8)+((blue&0xFF)<<16);
}
public void validate(int iteration)
{
if (iteration == 0) { return; }
int compt = 0;
int tr = 0;
int tb = 0;
int tg = 0;
for(int i=0;i<2;i++)
{
for(int j=0;j<2;j++)
{
for(int k=0;k<2;k++)
{
OctreeCell c = childs[i][j][k];
if(c!=null)
{
c.validate(iteration-1);
compt++;
tr += ((int)c.red)&0xFF;
tg += ((int)c.green)&0xFF;
tb += ((int)c.blue)&0xFF;
}
}
}
}
red = (byte)((tr/compt)&0xFF);
green = (byte)((tg/compt)&0xFF);
blue = (byte)((tb/compt)&0xFF);
}
}
Ray casting :
protected int casteRay(float cameraX,float cameraY,float cameraZ,
float viewX,float viewY,float viewZ)
{
float dist = MIN_DIST;
while(dist<MAX_DIST)
{
float cx = cameraX+viewX*dist;
float cy = cameraY+viewY*dist;
float cz = cameraZ+viewZ*dist;
int pixelSize = (int)(dist/SCREEN_DIST);
if(pixelSize<1) { pixelSize = 1; }
else if(pixelSize>16) { pixelSize = 16; }
cx -= octree.x;
cy -= octree.y;
cz -= octree.z;
if ((cx>=0)&&(cx<octree.sx)&&
(cy>=0)&&(cy<octree.sy)&&
(cz>=0)&&(cz<octree.sz))
{
int ite = octree.depth-INV_POW2[pixelSize];
OctreeCell c = octree.getRoot().get(ite, cx/octree.sx, cy/octree.sy, cz/octree.sz);
if (c != null)
{
return c.getColor();
}
}
dist += pixelSize*0.25f;
}
return 0;
}
With the octree search and the stepping casting, I don’t really like this thing.
What I don’t like too is that we simply replace a bunch of triangles by a bunch of voxels. When zooming, it will be the same problem. I would prefere to use a ray tracing base on nurbs with procedural/factal texture but it is not realistic… An artist will never deal with too mush abstract concepts. Thought I would prefere nurbs with displacement map (but calculations are not that simple)