void SaveAsRaw(int size, int channels, string fileName, RenderTexture rtex) { ComputeBuffer buffer = new ComputeBuffer(size, sizeof(float) * channels); CBUtility.ReadFromRenderTexture(rtex, channels, buffer, m_readData); float[] data = new float[size * channels]; buffer.GetData(data); byte[] byteArray = new byte[size * 4 * channels]; System.Buffer.BlockCopy(data, 0, byteArray, 0, byteArray.Length); System.IO.File.WriteAllBytes(Application.dataPath + m_filePath + fileName + ".raw", byteArray); buffer.Release(); }
void SaveAs8bit(int width, int height, int channels, string fileName, RenderTexture rtex, float scale = 1.0f) { //Only used to get a visible image for debugging. ComputeBuffer buffer = new ComputeBuffer(width * height, sizeof(float) * channels); CBUtility.ReadFromRenderTexture(rtex, channels, buffer, m_readData); float[] data = new float[width * height * channels]; buffer.GetData(data); Texture2D tex = new Texture2D(width, height); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { Color col = new Color(0, 0, 0, 1); col.r = data[(x + y * width) * channels + 0]; if (channels > 1) { col.g = data[(x + y * width) * channels + 1]; } if (channels > 2) { col.b = data[(x + y * width) * channels + 2]; } tex.SetPixel(x, y, col * scale); } } tex.Apply(); byte[] bytes = tex.EncodeToPNG(); System.IO.File.WriteAllBytes(Application.dataPath + m_filePath + fileName + ".png", bytes); buffer.Release(); }
void GenerateWavesSpectrum() { // Slope variance due to all waves, by integrating over the full spectrum. // Used by the BRDF rendering model float theoreticSlopeVariance = 0.0f; float k = 5e-3f; while (k < 1e3f) { float nextK = k * 1.001f; theoreticSlopeVariance += k * k * Spectrum(k, 0, true) * (nextK - k); k = nextK; } float[] spectrum01 = new float[m_fourierGridSize * m_fourierGridSize * 4]; float[] spectrum23 = new float[m_fourierGridSize * m_fourierGridSize * 4]; int idx; float i; float j; float totalSlopeVariance = 0.0f; Vector2 sample12XY; Vector2 sample12ZW; Vector2 sample34XY; Vector2 sample34ZW; UnityEngine.Random.seed = 0; for (int x = 0; x < m_fourierGridSize; x++) { for (int y = 0; y < m_fourierGridSize; y++) { idx = x + y * m_fourierGridSize; i = (x >= m_fourierGridSize / 2) ? (float)(x - m_fourierGridSize) : (float)x; j = (y >= m_fourierGridSize / 2) ? (float)(y - m_fourierGridSize) : (float)y; sample12XY = GetSpectrumSample(i, j, m_gridSizes.x, Mathf.PI / m_gridSizes.x); sample12ZW = GetSpectrumSample(i, j, m_gridSizes.y, Mathf.PI * m_fsize / m_gridSizes.x); sample34XY = GetSpectrumSample(i, j, m_gridSizes.z, Mathf.PI * m_fsize / m_gridSizes.y); sample34ZW = GetSpectrumSample(i, j, m_gridSizes.w, Mathf.PI * m_fsize / m_gridSizes.z); spectrum01[idx * 4 + 0] = sample12XY.x; spectrum01[idx * 4 + 1] = sample12XY.y; spectrum01[idx * 4 + 2] = sample12ZW.x; spectrum01[idx * 4 + 3] = sample12ZW.y; spectrum23[idx * 4 + 0] = sample34XY.x; spectrum23[idx * 4 + 1] = sample34XY.y; spectrum23[idx * 4 + 2] = sample34ZW.x; spectrum23[idx * 4 + 3] = sample34ZW.y; i *= 2.0f * Mathf.PI; j *= 2.0f * Mathf.PI; totalSlopeVariance += GetSlopeVariance(i / m_gridSizes.x, j / m_gridSizes.x, sample12XY); totalSlopeVariance += GetSlopeVariance(i / m_gridSizes.y, j / m_gridSizes.y, sample12ZW); totalSlopeVariance += GetSlopeVariance(i / m_gridSizes.z, j / m_gridSizes.z, sample34XY); totalSlopeVariance += GetSlopeVariance(i / m_gridSizes.w, j / m_gridSizes.w, sample34ZW); } } //Write floating point data into render texture m_writeFloat.WriteIntoRenderTexture(m_spectrum01, 4, spectrum01); m_writeFloat.WriteIntoRenderTexture(m_spectrum23, 4, spectrum23); if (!SystemInfo.supportsComputeShaders) { // Compute variance for the BRDF // copied from the dx9 project float slopeVarianceDelta = 0.5f * (theoreticSlopeVariance - totalSlopeVariance); // m_varianceMax = new Vector2(float.NegativeInfinity, float.NegativeInfinity); Vector2[, , ] variance32bit = new Vector2[m_varianceSize, m_varianceSize, m_varianceSize]; Color[] variance8bit = new Color[m_varianceSize * m_varianceSize * m_varianceSize]; // for (int x = 0; x < m_varianceSize; x++) { for (int y = 0; y < m_varianceSize; y++) { for (int z = 0; z < m_varianceSize; z++) { variance32bit [x, y, z] = ComputeVariance(slopeVarianceDelta, spectrum01, spectrum23, x, y, z); //problematic line if (variance32bit [x, y, z].x > m_varianceMax.x) { m_varianceMax.x = variance32bit [x, y, z].x; } if (variance32bit [x, y, z].y > m_varianceMax.y) { m_varianceMax.y = variance32bit [x, y, z].y; } } } } for (int x = 0; x < m_varianceSize; x++) { for (int y = 0; y < m_varianceSize; y++) { for (int z = 0; z < m_varianceSize; z++) { idx = x + y * m_varianceSize + z * m_varianceSize * m_varianceSize; variance8bit [idx] = new Color(variance32bit [x, y, z].x / m_varianceMax.x, variance32bit [x, y, z].y / m_varianceMax.y, 0.0f, 1.0f); } } } m_varianceTexture.SetPixels(variance8bit); m_varianceTexture.Apply(); m_maxSlopeVariance = 0.0f; for (int v = 0; v < m_varianceSize * m_varianceSize * m_varianceSize; v++) { m_maxSlopeVariance = Mathf.Max(m_maxSlopeVariance, variance8bit [v].r * m_varianceMax.x); m_maxSlopeVariance = Mathf.Max(m_maxSlopeVariance, variance8bit [v].g * m_varianceMax.y); } } else { m_varianceShader = ShaderReplacer.Instance.LoadedComputeShaders["SlopeVariance"]; m_varianceShader.SetFloat("_SlopeVarianceDelta", 0.5f * (theoreticSlopeVariance - totalSlopeVariance)); m_varianceShader.SetFloat("_VarianceSize", (float)m_varianceSize); m_varianceShader.SetFloat("_Size", m_fsize); m_varianceShader.SetVector("_GridSizes", m_gridSizes); m_varianceShader.SetTexture(0, "_Spectrum01", m_spectrum01); m_varianceShader.SetTexture(0, "_Spectrum23", m_spectrum23); m_varianceShader.SetTexture(0, "des", m_varianceRenderTexture); m_varianceShader.Dispatch(0, m_varianceSize / 4, m_varianceSize / 4, m_varianceSize / 4); //Find the maximum value for slope variance ComputeBuffer buffer = new ComputeBuffer(m_varianceSize * m_varianceSize * m_varianceSize, sizeof(float)); CBUtility.ReadFromRenderTexture(m_varianceRenderTexture, 1, buffer, ShaderReplacer.Instance.LoadedComputeShaders["ReadData"]); float[] varianceData = new float[m_varianceSize * m_varianceSize * m_varianceSize]; buffer.GetData(varianceData); m_maxSlopeVariance = 0.0f; for (int v = 0; v < m_varianceSize * m_varianceSize * m_varianceSize; v++) { m_maxSlopeVariance = Mathf.Max(m_maxSlopeVariance, varianceData[v]); } buffer.Release(); } }
/* * Updates the terrainQuads min and max values. Used to create a better fitting bounding box. * Is not essental and can be disabled if retriving the heights data from the GPU is causing * performance issues. */ void UpdateMinMax() { //if no quads need read back or if disabled return if (m_needReadBack.Count == 0 || !m_enableMinMaxReadBack) { return; } //Make a copy of all the keys of the tiles that need to be read back Tile.Id[] ids = new Tile.Id[m_needReadBack.Count]; m_needReadBack.Keys.CopyTo(ids, 0); //Sort the keys by there level, lowest -> highest System.Array.Sort(ids, new Tile.ComparerID()); int count = 0; //foreach key read back the tiles data until the maxReadBacksPerFrame limit is reached foreach (Tile.Id id in ids) { QuadTreeZ t = m_needReadBack[id]; //If elevations container already contains key then data has been //read back before so just reapply the min/max values to TerranQuad if (m_elevations.ContainsKey(id)) { ElevationInfo info = m_elevations.Get(id); t.quad.SetZMin(info.min); t.quad.SetZMax(info.max); m_needReadBack.Remove(id); } else { //if for some reason the tile is null remove from container and continue if (t.tile == null) { m_needReadBack.Remove(id); continue; } GPUTileStorage.GPUSlot slot = t.tile.GetSlot()[0] as GPUTileStorage.GPUSlot; //If for some reason this is not a GPUSlot remove and continue if (slot == null) { m_needReadBack.Remove(id); continue; } RenderTexture tex = slot.GetTexture(); int size = tex.width * tex.height; ElevationInfo info = new ElevationInfo(); info.elevations = new float[size]; //Read back heights data from texture CBUtility.ReadFromRenderTexture(tex, 1, m_elevationsBuffer, m_manager.GetReadData()); //Copy into elevations info m_elevationsBuffer.GetData(info.elevations); //Find the min/max values for (int i = 0; i < size; i++) { if (info.elevations[i] < info.min) { info.min = info.elevations[i]; } if (info.elevations[i] > info.max) { info.max = info.elevations[i]; } } //Update quad t.quad.SetZMin(info.min); t.quad.SetZMax(info.max); //Store elevations to prevent having to read back again soon //Add to end of container m_elevations.AddLast(id, info); m_needReadBack.Remove(id); count++; //If the number of rad back to do per frame has hit the limit stop loop. if (count >= m_maxReadBacksPerFrame) { break; } } } //If the number of elevation info to store has exceded limit remove from start of container while (m_elevations.Count() > m_maxStoredElevations) { m_elevations.RemoveFirst(); } }