// TODO: have a flag to invert the eyes (Cross Eye 3D), as mentioned in // TODO: http://forum.terasology.org/threads/happy-coding.1018/#post-11264 private void renderFinalStereoImage(WorldRenderer.WorldRenderingStage renderingStage) { if (renderingProcess.isNotTakingScreenshot()) { buffers.sceneFinal.bind(); } else { buffers.ocUndistorted.bind(); } switch (renderingStage) { case LEFT_EYE: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderFullscreenQuad(0, 0, fullScale.width() / 2, fullScale.height()); break; case RIGHT_EYE: // no glClear() here: the rendering for the second eye is being added besides the first // eye's rendering renderFullscreenQuad( fullScale.width() / 2 + 1, 0, fullScale.width() / 2, fullScale.height()); if (renderingProcess.isNotTakingScreenshot()) { graphicState.bindDisplay(); applyOculusDistortion(buffers.sceneFinal); } else { buffers.sceneFinal.bind(); applyOculusDistortion(buffers.ocUndistorted); renderingProcess.saveScreenshot(); // when saving a screenshot we do NOT send the image to screen, // to avoid the brief flicker of the screenshot for one frame } break; } }
// TODO: update javadoc when the rendering process becomes the FrameBuffersManager public void obtainStaticFBOs() { buffers.downSampledScene[4] = renderingProcess.getFBO("scene16"); buffers.downSampledScene[3] = renderingProcess.getFBO("scene8"); buffers.downSampledScene[2] = renderingProcess.getFBO("scene4"); buffers.downSampledScene[1] = renderingProcess.getFBO("scene2"); buffers.downSampledScene[0] = renderingProcess.getFBO("scene1"); }
// TODO: verify if this can be achieved entirely in the GPU, during tone mapping perhaps? public void downsampleSceneAndUpdateExposure() { if (renderingConfig.isEyeAdaptation()) { PerformanceMonitor.startActivity("Updating exposure"); downsampleSceneInto1x1pixelsBuffer(); renderingProcess .getCurrentReadbackPBO() .copyFromFBO( buffers.downSampledScene[0].fboId, 1, 1, GL12.GL_BGRA, GL11.GL_UNSIGNED_BYTE); renderingProcess.swapReadbackPBOs(); ByteBuffer pixels = renderingProcess.getCurrentReadbackPBO().readBackPixels(); if (pixels.limit() < 3) { logger.error("Failed to auto-update the exposure value."); return; } // TODO: make this line more readable by breaking it in smaller pieces currentSceneLuminance = 0.2126f * (pixels.get(2) & 0xFF) / 255.f + 0.7152f * (pixels.get(1) & 0xFF) / 255.f + 0.0722f * (pixels.get(0) & 0xFF) / 255.f; float targetExposure = hdrMaxExposure; if (currentSceneLuminance > 0) { targetExposure = hdrTargetLuminance / currentSceneLuminance; } float maxExposure = hdrMaxExposure; if (CoreRegistry.get(BackdropProvider.class).getDaylight() == 0.0) { // TODO: fetch the backdropProvider earlier and only once maxExposure = hdrMaxExposureNight; } if (targetExposure > maxExposure) { targetExposure = maxExposure; } else if (targetExposure < hdrMinExposure) { targetExposure = hdrMinExposure; } currentExposure = TeraMath.lerp(currentExposure, targetExposure, hdrExposureAdjustmentSpeed); } else { if (CoreRegistry.get(BackdropProvider.class).getDaylight() == 0.0) { currentExposure = hdrMaxExposureNight; } else { currentExposure = hdrExposureDefault; } } PerformanceMonitor.endActivity(); }
/** * Part of the deferred lighting technique, this method applies lighting through screen-space * calculations to the previously flat-lit world rendering stored in the primary FBO. // TODO: * rename sceneOpaque* FBOs to primaryA/B * * <p>See http://en.wikipedia.org/wiki/Deferred_shading as a starting point. */ public void applyLightBufferPass() { int texId = 0; GL13.glActiveTexture(GL13.GL_TEXTURE0 + texId); buffers.sceneOpaque.bindTexture(); materials.lightBufferPass.setInt("texSceneOpaque", texId++); GL13.glActiveTexture(GL13.GL_TEXTURE0 + texId); buffers.sceneOpaque.bindDepthTexture(); materials.lightBufferPass.setInt("texSceneOpaqueDepth", texId++); GL13.glActiveTexture(GL13.GL_TEXTURE0 + texId); buffers.sceneOpaque.bindNormalsTexture(); materials.lightBufferPass.setInt("texSceneOpaqueNormals", texId++); GL13.glActiveTexture(GL13.GL_TEXTURE0 + texId); buffers.sceneOpaque.bindLightBufferTexture(); materials.lightBufferPass.setInt("texSceneOpaqueLightBuffer", texId, true); buffers.sceneOpaquePingPong.bind(); graphicState.setRenderBufferMask(buffers.sceneOpaquePingPong, true, true, true); setViewportTo(buffers.sceneOpaquePingPong.dimensions()); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // TODO: verify this is necessary renderFullscreenQuad(); graphicState.bindDisplay(); // TODO: verify this is necessary setViewportToWholeDisplay(); // TODO: verify this is necessary renderingProcess.swapSceneOpaqueFBOs(); buffers.sceneOpaque.attachDepthBufferTo(buffers.sceneReflectiveRefractive); }
private void renderFinalMonoImage() { if (renderingProcess.isNotTakingScreenshot()) { graphicState.bindDisplay(); renderFullscreenQuad(0, 0, Display.getWidth(), Display.getHeight()); } else { buffers.sceneFinal.bind(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); renderFullscreenQuad(0, 0, fullScale.width(), fullScale.height()); renderingProcess.saveScreenshot(); // when saving a screenshot we do not send the image to screen, // to avoid the brief one-frame flicker of the screenshot // This is needed to avoid the UI (which is not currently saved within the // screenshot) being rendered for one frame with buffers.sceneFinal size. setViewportToWholeDisplay(); } }
/** * Adds outlines and ambient occlusion to the rendering obtained so far stored in the primary FBO. * Stores the resulting output back into the primary buffer. */ public void generatePrePostComposite() { materials.prePostComposite.enable(); // TODO: verify if there should be bound textures here. buffers.sceneOpaquePingPong.bind(); setViewportTo(buffers.sceneOpaquePingPong.dimensions()); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // TODO: verify this is necessary renderFullscreenQuad(); graphicState.bindDisplay(); // TODO: verify this is necessary setViewportToWholeDisplay(); // TODO: verify this is necessary renderingProcess.swapSceneOpaqueFBOs(); buffers.sceneOpaque.attachDepthBufferTo(buffers.sceneReflectiveRefractive); }
private void applyOculusDistortion(FBO inputBuffer) { materials.ocDistortion.enable(); int texId = 0; GL13.glActiveTexture(GL13.GL_TEXTURE0 + texId); inputBuffer.bindTexture(); materials.ocDistortion.setInt("texInputBuffer", texId, true); if (renderingProcess.isNotTakingScreenshot()) { updateOcShaderParametersForVP( 0, 0, fullScale.width() / 2, fullScale.height(), WorldRenderer.WorldRenderingStage.LEFT_EYE); renderFullscreenQuad(0, 0, Display.getWidth(), Display.getHeight()); updateOcShaderParametersForVP( fullScale.width() / 2 + 1, 0, fullScale.width() / 2, fullScale.height(), WorldRenderer.WorldRenderingStage.RIGHT_EYE); renderFullscreenQuad(0, 0, Display.getWidth(), Display.getHeight()); } else { // what follows -should- work also when there is no screenshot being taken, but somehow it // doesn't, hence the block above updateOcShaderParametersForVP( 0, 0, fullScale.width() / 2, fullScale.height(), WorldRenderer.WorldRenderingStage.LEFT_EYE); renderFullscreenQuad(0, 0, fullScale.width(), fullScale.height()); updateOcShaderParametersForVP( fullScale.width() / 2 + 1, 0, fullScale.width() / 2, fullScale.height(), WorldRenderer.WorldRenderingStage.RIGHT_EYE); renderFullscreenQuad(0, 0, fullScale.width(), fullScale.height()); } }
/** * In a number of occasions the rendering loop swaps two important FBOs. This method is used to * trigger the PostProcessor instance into refreshing the internal references to these FBOs. */ public void refreshSceneOpaqueFBOs() { buffers.sceneOpaque = renderingProcess.getFBO("sceneOpaque"); buffers.sceneOpaquePingPong = renderingProcess.getFBO("sceneOpaquePingPong"); }
// TODO: update javadoc when the rendering process becomes the FrameBuffersManager public void refreshDynamicFBOs() { // initial renderings buffers.sceneOpaque = renderingProcess.getFBO("sceneOpaque"); buffers.sceneOpaquePingPong = renderingProcess.getFBO("sceneOpaquePingPong"); buffers.sceneSkyBand0 = renderingProcess.getFBO("sceneSkyBand0"); buffers.sceneSkyBand1 = renderingProcess.getFBO("sceneSkyBand1"); buffers.sceneReflectiveRefractive = renderingProcess.getFBO("sceneReflectiveRefractive"); // sceneReflected, in case one wonders, is not used by the post-processor. // pre-post composite buffers.outline = renderingProcess.getFBO("outline"); buffers.ssao = renderingProcess.getFBO("ssao"); buffers.ssaoBlurred = renderingProcess.getFBO("ssaoBlurred"); // initial post-processing buffers.lightShafts = renderingProcess.getFBO("lightShafts"); buffers.initialPost = renderingProcess.getFBO("initialPost"); buffers.currentReadbackPBO = renderingProcess.getCurrentReadbackPBO(); buffers.sceneToneMapped = renderingProcess.getFBO("sceneToneMapped"); buffers.sceneHighPass = renderingProcess.getFBO("sceneHighPass"); buffers.sceneBloom0 = renderingProcess.getFBO("sceneBloom0"); buffers.sceneBloom1 = renderingProcess.getFBO("sceneBloom1"); buffers.sceneBloom2 = renderingProcess.getFBO("sceneBloom2"); buffers.sceneBlur0 = renderingProcess.getFBO("sceneBlur0"); buffers.sceneBlur1 = renderingProcess.getFBO("sceneBlur1"); // final post-processing buffers.ocUndistorted = renderingProcess.getFBO("ocUndistorted"); buffers.sceneFinal = renderingProcess.getFBO("sceneFinal"); fullScale = buffers.sceneOpaque.dimensions(); }