//queary public BTerrainVisual.eLODLevel getLODLevel(Vector3 pt, Vector3 Eye) { if (!TerrainGlobals.getVisual().isDynamicLODEnabled()) { return(TerrainGlobals.getVisual().getStaticLODLevel()); } Vector3 d = pt - Eye; float dist = d.Length(); if (dist > (float)BTerrainVisual.eLODLevelDists.cLOD3Dist) { return(BTerrainVisual.eLODLevel.cLOD3); } else if (dist > (float)BTerrainVisual.eLODLevelDists.cLOD2Dist) { return(BTerrainVisual.eLODLevel.cLOD2); } else if (dist > (float)BTerrainVisual.eLODLevelDists.cLOD1Dist) { return(BTerrainVisual.eLODLevel.cLOD1); } return(BTerrainVisual.eLODLevel.cLOD0); }
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; }
public bool render() { if (mSetVBs.Count == 0) { createRenderVBs(); if (mSetVBs.Count == 0) { return(false); } } BRenderDevice.getDevice().VertexDeclaration = VertexTypes.Pos.vertDecl; //my shader is started in the parent FoliageManager class.. BTerrainQuadNode qn = TerrainGlobals.getTerrain().getQuadNodeLeafArray()[mOwnerQNIndex]; //find our visual handle index //CLM the skirts f**k this up.. just find the highest LOD that's valid... BTerrainVisualDataHandle vdh = null; for (int i = 0; i < (int)Terrain.BTerrainVisual.eLODLevel.cLODCount; i++) { if (qn.mVisualDataIndxPerLOD[i] != -1) { vdh = TerrainGlobals.getVisual().getVisualHandle(qn.mVisualDataIndxPerLOD[i]); break; } } if (vdh == null) { return(false); } //bind my QN positions texture FoliageManager.mFoliageGPUShader.mShader.SetValue(FoliageManager.mTerrainQNPosTexture, vdh.mHandle.mPositionsTexture); Vector4 QnData = new Vector4((BTerrainQuadNode.getMaxNodeWidth() >> vdh.LOD), TerrainGlobals.getTerrain().getTileScale(), mOwnerNodeDesc.mMinXVert, mOwnerNodeDesc.mMinZVert); FoliageManager.mFoliageGPUShader.mShader.SetValue(FoliageManager.mTerrainQNData, QnData); for (int setI = 0; setI < mSetsUsed.Count; setI++) { FoliageSet set = FoliageManager.giveSet(mSetsUsed[setI]); float rcpBladeImgWidth = 1.0f / (float)set.mNumBlades; FoliageManager.mFoliageGPUShader.mShader.SetValue(FoliageManager.mSetRCPBladeTexWidth, rcpBladeImgWidth); FoliageManager.mFoliageGPUShader.mShader.SetValue(FoliageManager.mSetAlbedoTexture, set.mD3DAlbedoTexture == null? BRenderDevice.getTextureManager().getDefaultTexture(TextureManager.eDefaultTextures.cDefTex_Red): set.mD3DAlbedoTexture.mTexture); FoliageManager.mFoliageGPUShader.mShader.SetValue(FoliageManager.mSetOpacityTexture, set.mD3DOpacityTexture == null ? BRenderDevice.getTextureManager().getDefaultTexture(TextureManager.eDefaultTextures.cDefTex_White) : set.mD3DOpacityTexture.mTexture); FoliageManager.mFoliageGPUShader.mShader.SetValue(FoliageManager.mSetPositionsTexture, set.mD3DPositionsTexture); FoliageManager.mFoliageGPUShader.mShader.SetValue(FoliageManager.mSetUVsTexture, set.mD3DUVsTexture); //DRAW US FOOL! BRenderDevice.getDevice().SetStreamSource(0, mSetVBs[setI], 0); BRenderDevice.getDevice().Indices = mSetIBs[setI]; FoliageManager.mFoliageGPUShader.mShader.CommitChanges(); BRenderDevice.getDevice().DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, mSetVertCount[setI], 0, mSetPolyCount[setI]); } return(true); }
//----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- public void computeHeightFieldDirectFloat(uint width, uint height, bool includeSimMod, Vector3 upDir, bool onlyDoOneSample, ref float[] output) { copyTempD3DValues(); TerrainGlobals.getTerrain().getQuadNodeRoot().clearVisibleDatHandle(); TerrainGlobals.getVisual().destroyAllHandles(); TerrainGlobals.getVisual().setHandleGenMode(true); GC.WaitForPendingFinalizers(); ExportTo360.checkLoadRender(); createTempTextures(width, height); calculateWorldBounds(includeSimMod); mHeightFieldAttributes = new BHeightFieldAttributes(width, height); Matrix worldToView = Matrix.Identity; Matrix viewToProj = Matrix.Identity; BBoundingBox worldBounds = new BBoundingBox(); double worldMinY = 0, worldMaxY = 0; computeTransforms(upDir, ref worldToView, ref viewToProj, ref worldBounds, ref worldMinY, ref worldMaxY); float mWorldRangeY = (float)(mWorldMax.Y - mWorldMin.Y); uint numVals = width * height; if (output == null || output.Length != numVals) { output = new float[numVals]; for (uint i = 0; i < numVals; i++) { output[i] = float.MinValue; } } uint cNumSamples = (uint)(onlyDoOneSample?1:4); Random rand = new Random(); for (uint sampleIndex = 0; sampleIndex < cNumSamples; sampleIndex++) { float xOfs = sampleIndex != 0 ? (float)((rand.NextDouble() * 2) - 1) : 0.0f; float yOfs = sampleIndex != 0 ? (float)((rand.NextDouble() * 2) - 1) : 0.0f; Matrix projOfs = Matrix.Translation(xOfs / width, yOfs / height, 0.0f); generateHeightBuffer(ref pHighDepthSurf, width, height, true, worldToView, viewToProj * projOfs, includeSimMod); #region fill & lock //mWorldMin.Y += 1.0f; //mWorldMax.Y -= 1.0f; unsafe { GraphicsStream texstreamHI = pHighDepths.LockRectangle(0, LockFlags.None); float * pSrcHigh = (float *)texstreamHI.InternalDataPointer; //copy the data out so we can screw with it. for (uint c = 0; c < numVals; c++) { output[c] = (float)Math.Max(output[c], pSrcHigh[c]); } pHighDepths.UnlockRectangle(0); } //find the max & min depth for this slice #endregion } releaseTempTextures(); restoreTempD3DValues(); TerrainGlobals.getVisual().setHandleGenMode(false); ExportTo360.checkUnloadRender(); //#region dumpHeightfiled //{ // FileStream s = File.Open("_outHiDirect.raw", FileMode.OpenOrCreate, FileAccess.Write); // BinaryWriter f = new BinaryWriter(s); // for (int i = 0; i < width * height; i++) // { // float kp = (output[i] - mWorldMin.Y) / mWorldRangeY; // ushort op = (ushort)(kp * ushort.MaxValue); // f.Write(op); // } // f.Close(); // s.Close(); //} //#endregion }
public void computeHeightField(uint width, uint height, bool includeSimMod, Vector3 upDir, uint cNumSamples) { copyTempD3DValues(); TerrainGlobals.getTerrain().getQuadNodeRoot().clearVisibleDatHandle(); TerrainGlobals.getVisual().destroyAllHandles(); TerrainGlobals.getVisual().setHandleGenMode(true); GC.WaitForPendingFinalizers(); ExportTo360.checkLoadRender(); createTempTextures(width, height); calculateWorldBounds(includeSimMod); mHeightFieldAttributes = new BHeightFieldAttributes(width, height); Matrix worldToView = Matrix.Identity; Matrix viewToProj = Matrix.Identity; BBoundingBox worldBounds = new BBoundingBox(); double worldMinY = 0, worldMaxY = 0; computeTransforms(upDir, ref worldToView, ref viewToProj, ref worldBounds, ref worldMinY, ref worldMaxY); Random rand = new Random(); double minDepth = float.MaxValue; double maxDepth = float.MinValue; cNumSamples = (uint)BMathLib.Clamp(cNumSamples, 1, 32); for (uint sampleIndex = 0; sampleIndex < cNumSamples; sampleIndex++) { float xOfs = sampleIndex != 0 ? (float)((rand.NextDouble() * 2) - 1) : 0.0f; float yOfs = sampleIndex != 0 ? (float)((rand.NextDouble() * 2) - 1) : 0.0f; Matrix projOfs = Matrix.Translation(xOfs / width, yOfs / height, 0.0f); generateDepthBuffer(ref pHighDepthSurf, width, height, false, worldToView, viewToProj * projOfs, includeSimMod); generateDepthBuffer(ref pLowDepthSurf, width, height, true, worldToView, viewToProj * projOfs, includeSimMod); fillHeightFieldTexture(width, height, mHeightFieldAttributes, pLowDepths, pHighDepths, ref minDepth, ref maxDepth); } viewToProj = viewToProj * Matrix.Translation(0.0f, 0.0f, (float)(-minDepth)) * Matrix.Scaling(1.0f, 1.0f, (float)(1.0f / (maxDepth - minDepth))); double newWorldMinY = worldMinY + (worldMaxY - worldMinY) * minDepth; worldMaxY = worldMinY + (worldMaxY - worldMinY) * maxDepth; worldMinY = newWorldMinY; minDepth = 0.0f; maxDepth = 1.0f; mHeightFieldAttributes.mWidth = width; mHeightFieldAttributes.mHeight = height; mHeightFieldAttributes.mBounds = worldBounds; mHeightFieldAttributes.mWorldMinY = (float)worldMinY; mHeightFieldAttributes.mWorldMaxY = (float)worldMaxY; mHeightFieldAttributes.mWorldRangeY = (float)(worldMaxY - worldMinY); float minZ = 0; float maxZ = 1; float x = 0; float y = 0; Matrix cMTProjToScreen = BMathLib.matrixFrom16floats( width * .5f, 0.0f, 0.0f, 0.0f, 0.0f, height * -.5f, 0.0f, 0.0f, 0.0f, 0.0f, maxZ - minZ, 0.0f, x + width * .5f, y + height * .5f, minZ, 1.0f); mHeightFieldAttributes.mWorldToNormZ = worldToView * viewToProj * cMTProjToScreen; Matrix screenToProj = Matrix.Invert(cMTProjToScreen); Matrix projToView = Matrix.Invert(viewToProj); Matrix cMTScreenToView = Matrix.Multiply(screenToProj, projToView); mHeightFieldAttributes.mNormZToWorld = cMTScreenToView * Matrix.Invert(worldToView); releaseTempTextures(); restoreTempD3DValues(); TerrainGlobals.getVisual().setHandleGenMode(false); ExportTo360.checkUnloadRender(); //copy our pixels from the previous point { for (int q = 0; q < width; q++) { mHeightFieldAttributes.mpTexelsLO[(width - 1) * width + q] = mHeightFieldAttributes.mpTexelsLO[(width - 2) * width + q]; mHeightFieldAttributes.mpTexelsLO[q * width + (width - 1)] = mHeightFieldAttributes.mpTexelsLO[q * width + (width - 2)]; mHeightFieldAttributes.mpTexelsLO[q] = mHeightFieldAttributes.mpTexelsLO[width + q]; mHeightFieldAttributes.mpTexelsLO[q * width] = mHeightFieldAttributes.mpTexelsLO[q * width + (1)]; mHeightFieldAttributes.mpTexelsHI[(width - 1) * width + q] = mHeightFieldAttributes.mpTexelsHI[(width - 2) * width + q]; mHeightFieldAttributes.mpTexelsHI[q * width + (width - 1)] = mHeightFieldAttributes.mpTexelsHI[q * width + (width - 2)]; mHeightFieldAttributes.mpTexelsHI[q] = mHeightFieldAttributes.mpTexelsHI[width + q]; mHeightFieldAttributes.mpTexelsHI[q * width] = mHeightFieldAttributes.mpTexelsHI[q * width + (1)]; } } #region dumpHeightfiled //{ // FileStream s = File.Open(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory) + "\\out.raw", FileMode.OpenOrCreate, FileAccess.Write); // BinaryWriter f = new BinaryWriter(s); // for (int i = 0; i < width * height; i++) // { // f.Write(mHeightFieldAttributes.mpTexelsLO[i]); // f.Write(mHeightFieldAttributes.mpTexelsHI[i]); // } // f.Close(); // s.Close(); //} #endregion }