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 }
//----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- 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 }
//----------------------------------------------------------------------------------- //----------------------------------------------------------------------------------- unsafe void fillHeightFieldTexture( uint width, uint height, BHeightFieldAttributes heightAttribs, Texture pLowDepths, Texture pHighDepths, ref double minDepthF, ref double maxDepthF) { GraphicsStream texstreamLOW = pLowDepths.LockRectangle(0, LockFlags.None); float * pSrcLow = (float *)texstreamLOW.InternalDataPointer; GraphicsStream texstreamHI = pHighDepths.LockRectangle(0, LockFlags.None); float * pSrcHigh = (float *)texstreamHI.InternalDataPointer; bool firstPass = (minDepthF == float.MaxValue); //find the max & min depth for this slice uint numVals = width * height; if (minDepthF == float.MaxValue) { minDepthF = float.MaxValue; maxDepthF = 0; for (uint c = 0; c < numVals; c++) { float l = pSrcLow[c]; float h = pSrcHigh[c]; if (!BMathLib.compare(l, 1) && !BMathLib.compare(l, 0)) { if (l < minDepthF) { minDepthF = l; } if (l > maxDepthF) { maxDepthF = l; } } if (!BMathLib.compare(h, 1) && !BMathLib.compare(h, 0)) { if (h < minDepthF) { minDepthF = h; } if (h > maxDepthF) { maxDepthF = h; } } } if (BMathLib.compare((float)minDepthF, float.MaxValue)) { minDepthF = 0; maxDepthF = 1; } if (BMathLib.compare((float)minDepthF, (float)maxDepthF)) { if (minDepthF == 0) { maxDepthF++; } else { minDepthF--; } } } //add the depth values to the array, compress them based upon difference float diff = (float)(maxDepthF - minDepthF); for (uint c = 0; c < numVals; c++) { float l = pSrcLow[c]; if (!BMathLib.compare(l, 1) && !BMathLib.compare(l, 0)) { if (l < minDepthF) { l = (float)minDepthF; } else if (l > maxDepthF) { l = (float)maxDepthF; } } float h = pSrcHigh[c]; if (!BMathLib.compare(h, 1) && !BMathLib.compare(h, 0)) { if (h < minDepthF) { h = (float)minDepthF; } else if (h > maxDepthF) { h = (float)maxDepthF; } } h = ((float)(h - minDepthF) / diff); l = ((float)(l - minDepthF) / diff); int shortRange = 0xFFFF; ushort hiVal = (ushort)BMathLib.Clamp((shortRange * h), 0, ushort.MaxValue); ushort loVal = (ushort)BMathLib.Clamp((shortRange * l), 0, ushort.MaxValue); if (firstPass) { //if(loVal != 0xFFFF && loVal != 0) heightAttribs.mpTexelsLO[c] = loVal; //if (hiVal != 0xFFFF && hiVal != 0) heightAttribs.mpTexelsHI[c] = hiVal; } else { // if (loVal != 0xFFFF && loVal != 0) heightAttribs.mpTexelsLO[c] = (ushort)Math.Min(heightAttribs.mpTexelsLO[c], loVal); // if (hiVal != 0xFFFF && hiVal != 0) heightAttribs.mpTexelsHI[c] = (ushort)Math.Min(heightAttribs.mpTexelsHI[c], hiVal); } } //fill in any blank spots that might be conflicting.. //for (uint y = 0; y < height; y++) //{ // for (uint x = 0; x < width; x++) // { // uint ofs = x + y * mHeightFieldAttributes.mWidth; // uint l = heightAttribs.mpTexelsLO[ofs]; // uint h = heightAttribs.mpTexelsHI[ofs]; // bool modified = false; // if (l == 0) // { // float ave = 0.0f; // uint num = 0; // for (int xd = -1; xd < 1; xd++) // { // int yd; // for (yd = -1; yd < 1; yd++) // { // int xx = (int)BMathLib.Clamp(xd + x, 0, width - 1); // int yy = (int)BMathLib.Clamp(yd + y, 0, height - 1); // uint p = heightAttribs.mpTexelsLO[xx + yy * mHeightFieldAttributes.mWidth];//lowHeights(xx, yy); // if (p != 0) // { // ave += p; // num++; // } // } // } // if (num != 0) // { // l = (uint)BMathLib.Clamp(BMathLib.FloatToIntRound(ave / num), 0, 65535U); // heightAttribs.mpTexelsLO[ofs] = (ushort)l; // } // } // modified = false; // if (h == 1) // { // float ave = 0.0f; // uint num = 0; // for (int xd = -2; xd < 2; xd++) // { // int yd; // for (yd = -2; yd < 2; yd++) // { // int xx = (int)BMathLib.Clamp(xd + x, 0, width - 1); // int yy = (int)BMathLib.Clamp(yd + y, 0, height - 1); // uint p = heightAttribs.mpTexelsHI[xx + yy * mHeightFieldAttributes.mWidth];//highHeights(xx, yy); // if (p != 0) // { // ave += p; // num++; // } // } // } // if (num != 0) // { // h = (uint)BMathLib.Clamp(BMathLib.FloatToIntRound(ave / num), 0, 65535U); // heightAttribs.mpTexelsHI[ofs] = (ushort)h; // } // } // } //} pLowDepths.UnlockRectangle(0); pHighDepths.UnlockRectangle(0); }