private void raytrace(Ray ray) { double[] nearfar = new double[2]; enterBlock(ray, nearfar); double tNear = nearfar[0]; double tFar = nearfar[1]; ray.color.set(1, 1, 1, 1); if (tNear <= tFar && tFar >= 0) { ray.o.scaleAdd(tNear, ray.d); ray.distance += tNear; if (blockId == -1) { renderTestModel(ray); } else { if (showCompass) { renderCompass(ray); } ray.setPrevMat(Block.AIR, 0); Block theBlock = Block.get(blockId); ray.setCurrentMat(theBlock, blockId); theBlock.intersect(ray, scene); } } }
/** Raytrace one frame. */ private void raytrace() { double aspect = width / (double) height; Ray ray = new Ray(); camPos.set(0, -distance, 0); transform.transform(camPos); camPos.add(.5, .5, .5); for (int x = 0; x < width; ++x) { double rayx = fovTan * aspect * (.5 - ((double) x) / width); for (int y = 0; y < height; ++y) { ray.setDefault(); ray.d.set(rayx, 1, fovTan * (.5 - ((double) y) / height)); ray.d.normalize(); transform.transform(ray.d); ray.o.set(camPos); raytrace(ray); ray.color.x = QuickMath.min(1, FastMath.sqrt(ray.color.x)); ray.color.y = QuickMath.min(1, FastMath.sqrt(ray.color.y)); ray.color.z = QuickMath.min(1, FastMath.sqrt(ray.color.z)); backBuffer.setRGB(x, y, Color.getRGB(ray.color)); } } }
private void renderCompass(Ray ray) { ray.t = Double.POSITIVE_INFINITY; for (int i = 0; i < quads.length; ++i) { if (quads[i].intersect(ray)) { ray.t = ray.tNext; tex[i].getColor(ray); } } }
/** @return Next ray from free list */ public final Ray get() { Ray ray; if (size == 0) { ray = new Ray(); } else { ray = pool[--size]; } ray.setDefault(); return ray; }
/** * @param other * @return Next ray from free list */ public final Ray get(Ray other) { Ray ray; if (size == 0) { ray = new Ray(); } else { ray = pool[--size]; } ray.set(other); return ray; }
public static boolean intersect(Ray ray) { boolean hit = false; ray.t = Double.POSITIVE_INFINITY; for (Quad face : faces[ray.getBlockData() % 6]) { if (face.intersect(ray)) { Texture.oakPlanks.getColor(ray); ray.n.set(face.n); ray.t = ray.tNear; hit = true; } } if (hit) { ray.color.w = 1; ray.distance += ray.t; ray.x.scaleAdd(ray.t, ray.d, ray.x); } return hit; }
/** * @param scene * @param ray * @return <code>true</code> if exited water */ private boolean exitWater(Scene scene, Ray ray) { int level; Octree.Node node; int lx, ly, lz; int x, y, z; double nx, ny, nz; double xx, xy, xz; double cx, cy, cz, cw; double distance; while (true) { Block.WATER.intersect(ray, scene); ray.n.x = -ray.n.x; ray.n.y = -ray.n.y; ray.n.z = -ray.n.z; xx = ray.x.x; xy = ray.x.y; xz = ray.x.z; nx = ray.n.x; ny = ray.n.y; nz = ray.n.z; cx = ray.color.x; cy = ray.color.y; cz = ray.color.z; cw = ray.color.w; distance = ray.distance; // add small offset past the intersection to avoid // recursion to the same octree node! x = (int) QuickMath.floor(ray.x.x + ray.d.x * Ray.OFFSET); y = (int) QuickMath.floor(ray.x.y + ray.d.y * Ray.OFFSET); z = (int) QuickMath.floor(ray.x.z + ray.d.z * Ray.OFFSET); node = root; level = depth; lx = x >>> level; ly = y >>> level; lz = z >>> level; if (lx != 0 || ly != 0 || lz != 0) { // ray origin is outside octree! ray.currentMaterial = Block.AIR.id; return true; } while (node.type == -1) { level -= 1; lx = x >>> level; ly = y >>> level; lz = z >>> level; node = node.children[((lx & 1) << 2) | ((ly & 1) << 1) | (lz & 1)]; } Block currentBlock = Block.get(node.type); Block prevBlock = Block.get(ray.currentMaterial); ray.prevMaterial = ray.currentMaterial; ray.currentMaterial = node.type; if (currentBlock.localIntersect) { if (!currentBlock.intersect(ray, scene)) { ray.currentMaterial = Block.AIR.id; return true; } if (ray.distance > distance) { ray.x.set(xx, xy, xz); ray.n.set(nx, ny, nz); ray.color.set(cx, cy, cz, cw); ray.distance = distance; ray.currentMaterial = Block.AIR.id; return true; } else if (currentBlock == Block.WATER) { ray.x.scaleAdd(Ray.OFFSET, ray.d, ray.x); continue; } else { return true; } } if (currentBlock != prevBlock) { TexturedBlockModel.getIntersectionColor(ray); ray.n.scale(-1); return true; } } }
/** * Test whether the ray intersects any voxel before exiting the Octree. * * @param scene * @param ray the ray * @return <code>true</code> if the ray intersects a voxel */ public boolean intersect(Scene scene, Ray ray) { int level; Octree.Node node; boolean first = true; int lx, ly, lz; int x, y, z; int nx = 0, ny = 0, nz = 0; double tNear = Double.POSITIVE_INFINITY; double t; Vector3d d = ray.d; while (true) { // add small offset past the intersection to avoid // recursion to the same octree node! x = (int) QuickMath.floor(ray.x.x + ray.d.x * Ray.OFFSET); y = (int) QuickMath.floor(ray.x.y + ray.d.y * Ray.OFFSET); z = (int) QuickMath.floor(ray.x.z + ray.d.z * Ray.OFFSET); node = root; level = depth; lx = x >>> level; ly = y >>> level; lz = z >>> level; if (lx != 0 || ly != 0 || lz != 0) { // ray origin is outside octree! ray.currentMaterial = Block.AIR_ID; // only check octree intersection if this is the first iteration if (first) { // test if it is entering the octree t = -ray.x.x / d.x; if (t > Ray.EPSILON) { tNear = t; nx = 1; ny = nz = 0; } t = ((1 << level) - ray.x.x) / d.x; if (t < tNear && t > Ray.EPSILON) { tNear = t; nx = -1; ny = nz = 0; } t = -ray.x.y / d.y; if (t < tNear && t > Ray.EPSILON) { tNear = t; ny = 1; nx = nz = 0; } t = ((1 << level) - ray.x.y) / d.y; if (t < tNear && t > Ray.EPSILON) { tNear = t; ny = -1; nx = nz = 0; } t = -ray.x.z / d.z; if (t < tNear && t > Ray.EPSILON) { tNear = t; nz = 1; nx = ny = 0; } t = ((1 << level) - ray.x.z) / d.z; if (t < tNear && t > Ray.EPSILON) { tNear = t; nz = -1; nx = ny = 0; } if (tNear < Double.MAX_VALUE) { ray.x.scaleAdd(tNear, d, ray.x); ray.n.set(nx, ny, nz); ray.distance += tNear; tNear = Double.POSITIVE_INFINITY; continue; } else { return false; // outside of octree! } } else { return false; // outside of octree! } } first = false; while (node.type == -1) { level -= 1; lx = x >>> level; ly = y >>> level; lz = z >>> level; node = node.children[((lx & 1) << 2) | ((ly & 1) << 1) | (lz & 1)]; } // old octree visualization code /*double w = .1 * (1 + level); w*=w; if (ray.x.x < (lx<<level) + w && (ray.x.y < (ly<<level) + w || ray.x.y > ((ly+1)<<level) - w) || ray.x.x < (lx<<level) + w && (ray.x.z < (lz<<level) + w || ray.x.z > ((lz+1)<<level) - w) || ray.x.y < (ly<<level) + w && (ray.x.z < (lz<<level) + w || ray.x.z > ((lz+1)<<level) - w) || ray.x.x > ((lx+1)<<level) - w && (ray.x.y < (ly<<level) + w || ray.x.y > ((ly+1)<<level) - w) || ray.x.x > ((lx+1)<<level) - w && (ray.x.z < (lz<<level) + w || ray.x.z > ((lz+1)<<level) - w) || ray.x.y > ((ly+1)<<level) - w && (ray.x.z < (lz<<level) + w || ray.x.z > ((lz+1)<<level) - w)) { ray.color.x = .5; ray.color.y = .5; ray.color.z = .5; ray.color.w = 1; ray.prevMaterial = Block.AIR.id; ray.currentMaterial = 0xFF; return true; }*/ if (ray.currentMaterial == -1) { ray.prevMaterial = 0; ray.currentMaterial = node.type; } Block currentBlock = Block.get(node.type); Block prevBlock = Block.get(ray.currentMaterial); ray.prevMaterial = ray.currentMaterial; ray.currentMaterial = node.type; if (currentBlock.localIntersect) { if (currentBlock == Block.WATER && prevBlock == Block.WATER) { return exitWater(scene, ray); } if (currentBlock.intersect(ray, scene)) { if (prevBlock != currentBlock) return true; ray.x.scaleAdd(Ray.OFFSET, ray.d, ray.x); continue; } else { // exit ray from this local block ray.currentMaterial = 0; // current material is air ray.exitBlock(x, y, z); continue; } } else if (!currentBlock.isSameMaterial(prevBlock) && currentBlock != Block.AIR) { TexturedBlockModel.getIntersectionColor(ray); return true; } t = ((lx << level) - ray.x.x) / d.x; if (t > Ray.EPSILON) { tNear = t; nx = 1; ny = nz = 0; } else { t = (((lx + 1) << level) - ray.x.x) / d.x; if (t < tNear && t > Ray.EPSILON) { tNear = t; nx = -1; ny = nz = 0; } } t = ((ly << level) - ray.x.y) / d.y; if (t < tNear && t > Ray.EPSILON) { tNear = t; ny = 1; nx = nz = 0; } else { t = (((ly + 1) << level) - ray.x.y) / d.y; if (t < tNear && t > Ray.EPSILON) { tNear = t; ny = -1; nx = nz = 0; } } t = ((lz << level) - ray.x.z) / d.z; if (t < tNear && t > Ray.EPSILON) { tNear = t; nz = 1; nx = ny = 0; } else { t = (((lz + 1) << level) - ray.x.z) / d.z; if (t < tNear && t > Ray.EPSILON) { tNear = t; nz = -1; nx = ny = 0; } } ray.x.scaleAdd(tNear, d, ray.x); ray.n.set(nx, ny, nz); ray.distance += tNear; tNear = Double.POSITIVE_INFINITY; } }
private void renderTestModel(Ray ray) { renderCompass(ray); ray.t = Double.POSITIVE_INFINITY; testModel.intersect(ray); }