public void render(GLAutoDrawable drawable, SceneObject sceneRoot, Camera camera, Camera shadowCamera)
	{
		GL2 gl = drawable.getGL().getGL2();		
				
		try
		{
			/* Reset lights array. It will be re-filled as the scene is traversed. */
			
			/* 0.5. Compute sand dune buffer */
			if (simulateSandDune){
				int steps = (mInitialize==1 ? mSimulationSetupSteps: mSimulationSteps);
				for (int i=0; i < steps ; i++){
					computeSandDuneBuffer(gl);
				}
			}
			
			/* 1. Fill the gbuffer given this scene and camera. */ 
			fillGBuffer(gl, sceneRoot, camera);
			
			if (shadowCamera != null && shadowCamera.getEnableShadowMap()) {
				fillGBuffer(gl, sceneRoot, shadowCamera);
			}

			/* 2. Compute gradient buffer based on positions and normals, used for toon shading. */
			//computeGradientBuffer(gl);
			computeSSAOBuffer(gl, camera);
			
			/* 3. Apply deferred lighting to the g-buffer. At this point, the opaque scene has been rendered. */
			lightGBuffer(gl, camera, shadowCamera);

			/* 4. If we're supposed to preview one gbuffer texture, do that now. 
			 *    Otherwise, envoke the final render pass (optional post-processing). */
			if (mPreviewIndex == 2){
				Util.renderTextureFullscreen(gl, mSBufferFBO.getColorTexture(SBuffer_SandDune1Index));
			}
			else if (mPreviewIndex >= 0 && mPreviewIndex < GBuffer_FinalSceneIndex)
			{
				Util.renderTextureFullscreen(gl, mGBufferFBO.getColorTexture(mPreviewIndex));
			}
			else
			{			
				finalPass(gl, camera);					 								 
			}

		}
		catch (Exception err)
		{
			/* If an error occurs in all that, print it, but don't kill the whole program. */
			err.printStackTrace();
		}
	}