public void setCamera(Camera cameraParam) { camera = cameraParam; // set constants for terminating voxel traversal early if projected voxel size is less than 1 // pixel on the screen voxelSizeConstantA = camera.getDistanceToViewplane() * screenWidth; voxelSizeConstantB = camera.getViewplaneTop().length() / 2; }
public void render(Graphics g) { // make a copy of the camera to prevent artefacts from moving the camera during rendering Camera cameraFrame = new Camera(camera); // increment the number of frames rendered frameIndex++; // set constants for terminating voxel traversal early if projected voxel size is less than 1 // pixel on the screen. This small calculation is done once a // frame in case the camera's FOV has changed. voxelSizeConstantA = cameraFrame.getDistanceToViewplane() * screenWidth; voxelSizeConstantB = cameraFrame.getViewplaneTop().length() * 0.5d; // set the skipNode for this frame setSkipNode(cameraFrame.getPosition()); // make a thread executor to execute node rendering threads - one for each pixel ExecutorService rendererExecutor = Executors.newFixedThreadPool(NTHREADS); // for every pixel on the screen, cast a ray through it at the octreeModel for (int row = 0; row < screenHeight; row++) { for (int col = 0; col < screenWidth; col++) { Ray cameraRay = new Ray( cameraFrame.getPosition(), cameraFrame.getVectorToPixel(col, row, screenWidth, screenHeight)); if (skipNode != null) { RayCast rc = new RayCast( skipNode, skipNodeBoxMin, skipNodeBoxDim, cameraRay, row * screenHeight + col, imageColors, imageDepth, subdivider, voxelSizeConstantA, voxelSizeConstantB); rendererExecutor.execute(rc); } else { RayCast rc = new RayCast( rootNode, new Vector3d(-1, -1, -1), 2, cameraRay, row * screenHeight + col, imageColors, imageDepth, subdivider, voxelSizeConstantA, voxelSizeConstantB); rendererExecutor.execute(rc); } } } // shutdown the executor and wait for all threads to terminate rendererExecutor.shutdown(); try { rendererExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } catch (InterruptedException e) { e.printStackTrace(); } // do SSAO calculations and put results in imageShadows and get minimum tMin optTmin = SSAO.setOcclusion(imageDepth, screenHeight, screenWidth, imageShadows); // set the optimal tmin value to be used by camera movement optTmin = imageDepth[(screenWidth / 2) * screenHeight + (screenWidth / 2)] == Double.MAX_VALUE ? optTmin : imageDepth[(screenWidth / 2) * screenHeight + (screenWidth / 2)]; // adjust the colors in imageColors by the lighting in imageShadows to output the final colors // in imagePixelData for (int row = 0; row < screenHeight; row++) for (int col = 0; col < screenWidth; col++) imagePixelData[row * screenHeight + col] = ColorUtils.adjustLight( imageColors[row * screenHeight + col], imageShadows[row * screenHeight + col]); // save image if recording is enabled if (isRecording()) { try { File outputfile = new File("images/screenshot" + frameIndex + ".png"); ImageIO.write(backbuffer, "png", outputfile); } catch (IOException e) { System.err.println("file write IO exception"); } } // draw the image onto the graphics g.drawImage(backbuffer, 0, 0, null); backbuffer.flush(); // register that a frame has been drawn metrics.registerFrameRender(); // unify the bricks every 10 frames if (frameIndex % 10 == 0) brickManager.unifyBricks(); }