public void calcualteAO(eAOQuality quality, bool renderWorldObjects, ref float totalTime, ref float peelTime, ref float gatherTime, int startSampleIndex, int endSampleIndex) { totalTime = 0; peelTime = 0; gatherTime = 0; DateTime n = DateTime.Now; //should we multithread? if (CoreGlobals.mProcessorInfo.NumLogicalProcessors > 1) { mUsingMultithreading = true; AmbientOcclusion.IncrementCount = 0; AOIncrements = new int[TerrainGlobals.getTerrain().getNumXVerts() * TerrainGlobals.getTerrain().getNumZVerts()]; } else { mUsingMultithreading = false; } int width = 512; int height = 512; int numXSegments = 1; int numYSegments = 1; //special settings for Final mode if (quality == eAOQuality.cAO_Final) { numXSegments = 4; //what should these values really be? numYSegments = 4; // they should scale, so that huge terrain gets more segments.. // width = 1024; // height = 1024; // mUsingMultithreading = false; } //clear any handles available so we can use them as we see fit! TerrainGlobals.getTerrain().getQuadNodeRoot().clearVisibleDatHandle(); TerrainGlobals.getVisual().destroyAllHandles(); TerrainGlobals.getVisual().setHandleGenMode(true); blackoutAO(); //so we can gather light data Vector3 mWorldMin = Vector3.Empty; Vector3 mWorldMax = Vector3.Empty; BBoundingBox worldBounds = new BBoundingBox(); calculateWorldBounds(ref mWorldMin, ref mWorldMax, ref worldBounds, renderWorldObjects); mPeeler.init(width, height); Vector3 rayDir = -BMathLib.unitY; rayDir.Normalize(); Matrix worldToView = Matrix.Identity; Matrix viewToProj = Matrix.Identity; int numDesiredSamples = (int)Math.Sqrt((int)quality); int startIndex = 0; int endIndex = numDesiredSamples; List <Vector3> rayDirs = null; if (startSampleIndex != -1) { rayDirs = giveStratifiedOnHemiSphere(0, numDesiredSamples, false); startIndex = startSampleIndex; endIndex = Math.Min(endSampleIndex, rayDirs.Count); } else { rayDirs = giveStratifiedOnHemiSphere(0, numDesiredSamples, true); startIndex = 0; endIndex = rayDirs.Count; } float rcpNumSamples = 1.0f / (float)(rayDirs.Count); int numSamples = endIndex - startIndex; //begin our peel & gather process... bool ownBeginScene = !BRenderDevice.isInSceneRender(); if (ownBeginScene) { BRenderDevice.getDevice().BeginScene(); } for (int dc = startIndex; dc < endIndex; dc++) { //choose one rayDir = -rayDirs[dc]; computeWorldToView(ref rayDir, ref mWorldMin, ref mWorldMax, out worldToView); for (int x = 0; x < numXSegments; x++) { for (int y = 0; y < numYSegments; y++) { //calculate our lightspace projection matrix computeViewToProj(ref rayDir, worldBounds, worldToView, out viewToProj, numXSegments, numYSegments, x, y); //use worker threads.. gatherWorkerData wd = new gatherWorkerData(0, 0, TerrainGlobals.getTerrain().getNumXVerts(), TerrainGlobals.getTerrain().getNumZVerts(), width, height, rayDir, worldToView * viewToProj, rcpNumSamples); mPeeler.mDepthArray = null; mPeeler.mDepthArray = wd.fragList; //create our depth layers DateTime dpn = DateTime.Now; mPeeler.depthPeel(ref rayDir, ref worldToView, ref viewToProj, renderWorldObjects); TimeSpan dpts = DateTime.Now - dpn; peelTime += (float)dpts.TotalMinutes; //do final gathering (AO SPECIFIC) if (mUsingMultithreading) { finalGatherMultiThreaded(wd); } else { DateTime fgn = DateTime.Now; finalGatherSingleThreaded(wd); TimeSpan fgts = DateTime.Now - fgn; gatherTime += (float)fgts.TotalMinutes; } wd = null; mPeeler.mDepthArray = null; } } } if (ownBeginScene) { BRenderDevice.getDevice().EndScene(); } mPeeler.destroy(); TerrainGlobals.getVisual().setHandleGenMode(false); //if we're using multithreading, wait for all our worker threads to finish. if (mUsingMultithreading) { while (AmbientOcclusion.IncrementCount <= numSamples - 1) { Thread.Sleep(1); } float[] AOVals = TerrainGlobals.getEditor().getAmbientOcclusionValues(); for (int i = 0; i < AOIncrements.Length; i++) { AOVals[i] = AOIncrements[i] * rcpNumSamples; } } TimeSpan ts = DateTime.Now - n; totalTime = (float)ts.TotalMinutes; }