/// <summary> /// Save the actual data in table as a raw file to be loaded and used during run time. /// </summary> private 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(); }
public static void SaveAsRaw(int size, CBUtility.Channels channels, string fileName, string filePath, RenderTexture rtex, ComputeShader readDataComputeShader) { var channelsSize = (byte)channels; var buffer = new ComputeBuffer(size, sizeof(float) * channelsSize); CBUtility.ReadFromRenderTexture(rtex, channels, buffer, readDataComputeShader); var data = new float[size * channelsSize]; buffer.GetData(data); var byteArray = new byte[size * 4 * channelsSize]; Buffer.BlockCopy(data, 0, byteArray, 0, byteArray.Length); File.WriteAllBytes(Application.dataPath + filePath + fileName + ".raw", byteArray); buffer.Release(); }
public static void SaveAs8bit(int width, int height, CBUtility.Channels channels, string fileName, string filePath, RenderTexture rtex, ComputeShader readDataComputeShader, float scale = 1.0f) { var channelsSize = (byte)channels; var buffer = new ComputeBuffer(width * height, sizeof(float) * channelsSize); CBUtility.ReadFromRenderTexture(rtex, channels, buffer, readDataComputeShader); var data = new float[width * height * channelsSize]; buffer.GetData(data); var texture = new Texture2D(width, height); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { var color = new Color(0, 0, 0, 1); color.r = data[(x + y * width) * channelsSize + 0]; if (channelsSize > 1) { color.g = data[(x + y * width) * channelsSize + 1]; } if (channelsSize > 2) { color.b = data[(x + y * width) * channelsSize + 2]; } texture.SetPixel(x, y, color * scale); } } texture.Apply(); var bytes = texture.EncodeToPNG(); File.WriteAllBytes(Application.dataPath + filePath + fileName + ".png", bytes); buffer.Release(); }
private void ReadFromGPU(int numGrids) { if (!this.disableReadBack && this.readSdr == null) { Ocean.LogWarning("Trying to read GPU displacement data but the read shader is null"); } bool flag = SystemInfo.graphicsShaderLevel >= 50 && SystemInfo.supportsComputeShaders; if (!this.disableReadBack && this.readSdr != null && this.m_readBuffer != null && flag) { InterpolatedArray2f[] readDisplacements = this.DisplacementBuffer.GetReadDisplacements(); if (numGrids > 0) { CBUtility.ReadFromRenderTexture(this.m_displacementMaps[0], 3, this.m_readBuffer, this.readSdr); this.m_readBuffer.GetData(readDisplacements[0].Data); } else { readDisplacements[0].Clear(); } if (numGrids > 1) { CBUtility.ReadFromRenderTexture(this.m_displacementMaps[1], 3, this.m_readBuffer, this.readSdr); this.m_readBuffer.GetData(readDisplacements[1].Data); } else { readDisplacements[1].Clear(); } if (numGrids > 2) { CBUtility.ReadFromRenderTexture(this.m_displacementMaps[2], 3, this.m_readBuffer, this.readSdr); this.m_readBuffer.GetData(readDisplacements[2].Data); } else { readDisplacements[2].Clear(); } if (numGrids > 3) { } } }
/// <summary> /// Saves a 8 bit version of the table. /// Only used to get a visible image for debugging. /// </summary> private void SaveAs8bit(int width, int height, int channels, string fileName, RenderTexture rtex, float scale = 1.0f) { 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(); }
private void PrecomputeSkyboxAlltogether() { int texDepth = (int)_skyboxLUTSize.z; int texWidth = (int)_skyboxLUTSize.x; int texHeight = (int)_skyboxLUTSize.y; int floatSize = sizeof(float); int channels = 4; int texSize = texWidth * texHeight * texDepth; bool firstTime = false; if (_skyboxData == null) { firstTime = true; _skyboxData = new float[texSize * channels]; } ComputeBuffer buffer = new ComputeBuffer(texSize, floatSize * channels); // 4 bytes for float and 4 channels CBUtility.ReadFromRenderTexture(_skyboxLUT2, channels, buffer, FrostbiteReadShader); float[] data = new float[texSize * channels]; buffer.GetData(data); if (firstTime) { for (int i = 0; i < _skyboxData.Length; ++i) { _skyboxData[i] = data[i]; } } else { for (int i = 0; i < _skyboxData.Length; ++i) { _skyboxData[i] += data[i]; } } buffer.Release(); }
/// <summary> /// Updates the <see cref="TerrainQuad.ZMin"/> and <see cref="TerrainQuad.ZMax"/> 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. /// </summary> private void UpdateMinMax() { // If no quads need read back or if disabled return if (NeedsReadBackDictionary.Count == 0 || !EnableReadBack) { return; } // Make a copy of all the keys of the tiles that need to be read back var ids = new Tile.Id[NeedsReadBackDictionary.Count]; NeedsReadBackDictionary.Keys.CopyTo(ids, 0); // Sort the keys by there level, lowest -> highest Array.Sort(ids, new Tile.ComparerID()); var count = 0; // Foreach key read back the tiles data until the maxReadBacksPerFrame limit is reached foreach (var id in ids) { var treeZ = NeedsReadBackDictionary[id]; // If elevations container already contains key then data has been read back before so just reapply the [min, max] values to TerranQuad if (ElevationsDicionary.ContainsKey(id)) { var info = ElevationsDicionary.Get(id); treeZ.TerrainQuad.ZMin = info.Min; treeZ.TerrainQuad.ZMax = info.Max; NeedsReadBackDictionary.Remove(id); } else { // If for some reason the tile is null remove from container and continue if (treeZ.Tile == null) { NeedsReadBackDictionary.Remove(id); continue; } var slot = treeZ.Tile.Slot[0] as GPUTileStorage.GPUSlot; // If for some reason this is not a GPUSlot remove and continue if (slot == null) { NeedsReadBackDictionary.Remove(id); continue; } var texture = slot.Texture; var size = texture.width * texture.height; var elevationInfo = new ElevationInfo(); elevationInfo.Elevations = new float[size]; // Read back heights data from texture CBUtility.ReadFromRenderTexture(texture, CBUtility.Channels.R, ElevationsBuffer, GodManager.Instance.ReadData); // Copy into elevations info ElevationsBuffer.GetData(elevationInfo.Elevations); // Find the min/max values for (int i = 0; i < size; i++) { if (elevationInfo.Elevations[i] < elevationInfo.Min) { elevationInfo.Min = elevationInfo.Elevations[i]; } if (elevationInfo.Elevations[i] > elevationInfo.Max) { elevationInfo.Max = elevationInfo.Elevations[i]; } } // Update TerrainQuad treeZ.TerrainQuad.ZMin = elevationInfo.Min; treeZ.TerrainQuad.ZMax = elevationInfo.Max; // Store elevations to prevent having to read back again soon // Add to end of container ElevationsDicionary.AddLast(id, elevationInfo); NeedsReadBackDictionary.Remove(id); count++; // If the number of rad back to do per frame has hit the limit stop loop. if (count >= MaxReadBacksPerFrame) { break; } } } // If the number of elevation info to store has exceded limit remove from start of container while (ElevationsDicionary.Count() > MaxStoredElevations) { ElevationsDicionary.RemoveFirst(); } }
private void GenerateWavesSpectrum() { // Slope variance due to all waves, by integrating over the full spectrum. // Used by the BRDF rendering model var theoreticSlopeVariance = 0.0f; var k = 5e-3f; while (k < 1e3f) { var nextK = k * 1.001f; theoreticSlopeVariance += k * k * Spectrum(k, 0, true) * (nextK - k); k = nextK; } var spectrum01 = new float[FourierGridSize * FourierGridSize * 4]; var spectrum23 = new float[FourierGridSize * FourierGridSize * 4]; int idx; float i; float j; float totalSlopeVariance = 0.0f; Vector2 sample12XY = Vector2.zero; Vector2 sample12ZW = Vector2.zero; Vector2 sample34XY = Vector2.zero; Vector2 sample34ZW = Vector2.zero; Random.InitState(0); for (int x = 0; x < FourierGridSize; x++) { for (int y = 0; y < FourierGridSize; y++) { idx = x + y * FourierGridSize; i = (x >= FourierGridSize / 2) ? (float)(x - FourierGridSize) : (float)x; j = (y >= FourierGridSize / 2) ? (float)(y - FourierGridSize) : (float)y; sample12XY = GetSpectrumSample(i, j, GridSizes.x, Mathf.PI / GridSizes.x); sample12ZW = GetSpectrumSample(i, j, GridSizes.y, Mathf.PI * MapSize / GridSizes.x); sample34XY = GetSpectrumSample(i, j, GridSizes.z, Mathf.PI * MapSize / GridSizes.y); sample34ZW = GetSpectrumSample(i, j, GridSizes.w, Mathf.PI * MapSize / 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 / GridSizes.x, j / GridSizes.x, sample12XY); totalSlopeVariance += GetSlopeVariance(i / GridSizes.y, j / GridSizes.y, sample12ZW); totalSlopeVariance += GetSlopeVariance(i / GridSizes.z, j / GridSizes.z, sample34XY); totalSlopeVariance += GetSlopeVariance(i / GridSizes.w, j / GridSizes.w, sample34ZW); } } //Write floating point data into render texture var buffer = new ComputeBuffer(FourierGridSize * FourierGridSize, sizeof(float) * 4); buffer.SetData(spectrum01); CBUtility.WriteIntoRenderTexture(Spectrum01, CBUtility.Channels.RGBA, buffer, GodManager.Instance.WriteData); buffer.SetData(spectrum23); CBUtility.WriteIntoRenderTexture(Spectrum23, CBUtility.Channels.RGBA, buffer, GodManager.Instance.WriteData); buffer.Release(); var varianceShader = GodManager.Instance.Variance; varianceShader.SetFloat("_SlopeVarianceDelta", 0.5f * (theoreticSlopeVariance - totalSlopeVariance)); varianceShader.SetFloat("_VarianceSize", (float)VarianceSize); varianceShader.SetFloat("_Size", MapSize); varianceShader.SetVector("_GridSizes", GridSizes); varianceShader.SetTexture(0, "_Spectrum01", Spectrum01); varianceShader.SetTexture(0, "_Spectrum23", Spectrum23); varianceShader.SetTexture(0, "des", Variance); varianceShader.Dispatch(0, VarianceSize / 4, VarianceSize / 4, VarianceSize / 4); // Find the maximum value for slope variance buffer = new ComputeBuffer(VarianceSize * VarianceSize * VarianceSize, sizeof(float)); CBUtility.ReadFromRenderTexture(Variance, CBUtility.Channels.R, buffer, GodManager.Instance.ReadData); var varianceData = new float[VarianceSize * VarianceSize * VarianceSize]; buffer.GetData(varianceData); MaxSlopeVariance = 0.0f; for (int v = 0; v < VarianceSize * VarianceSize * VarianceSize; v++) { MaxSlopeVariance = Mathf.Max(MaxSlopeVariance, varianceData[v]); } buffer.Release(); }
public void SaveTextureAsKTX(RenderTexture rtex, String name, bool tile3D = false) { int texDepth = rtex.volumeDepth; int texWidth = rtex.width; int texHeight = rtex.height; int floatSize = sizeof(float); int channels = 4; bool tileEnabled = tile3D && texDepth > 1; if (tileEnabled) { texWidth *= texDepth; texDepth = 1; } int texSize = texWidth * texHeight * texDepth; ComputeBuffer buffer = new ComputeBuffer(texSize, floatSize * channels); // 4 bytes for float and 4 channels CBUtility.ReadFromRenderTexture(rtex, channels, buffer, FrostbiteReadShader); float[] data = new float[texSize * channels]; buffer.GetData(data); Byte[] header = { 0xAB, 0x4B, 0x54, 0x58, // first four bytes of Byte[12] identifier 0x20, 0x31, 0x31, 0xBB, // next four bytes of Byte[12] identifier 0x0D, 0x0A, 0x1A, 0x0A, // final four bytes of Byte[12] identifier 0x01, 0x02, 0x03, 0x04, // Byte[4] endianess (Big endian in this case) }; FileStream fs = new FileStream("Assets/Textures/" + name + ".ktx", FileMode.OpenOrCreate); BinaryWriter writer = new BinaryWriter(fs); writer.Write(header); UInt32 glType = 0x140B; // HALF UInt32 glTypeSize = 2; // 2 bytes UInt32 glFormat = 0x1908; // RGBA UInt32 glInterformat = 0x881A; // RGBA FLOAT16 UInt32 glBaseInternalFormat = 0x1908; // RGBA UInt32 width = (UInt32)texWidth; UInt32 height = (UInt32)texHeight; UInt32 depth = (UInt32)(texDepth == 1 ? 0 : texDepth); UInt32 numOfArrElem = 0; UInt32 numOfFace = 1; UInt32 numOfMip = 1; UInt32 bytesOfKeyVal = 0; writer.Write(glType); writer.Write(glTypeSize); writer.Write(glFormat); writer.Write(glInterformat); writer.Write(glBaseInternalFormat); writer.Write(width); writer.Write(height); writer.Write(depth); writer.Write(numOfArrElem); writer.Write(numOfFace); writer.Write(numOfMip); writer.Write(bytesOfKeyVal); UInt32 imageSize = (UInt32)(texSize * channels * glTypeSize); writer.Write(imageSize); if (tileEnabled) { for (int j = 0; j < rtex.height; j++) { for (int k = 0; k < rtex.volumeDepth; k++) { for (int i = 0; i < rtex.width; i++) { int startIndex = k * rtex.width * rtex.height * channels + j * rtex.width * channels + i * channels; writer.Write(Half.GetBytes((Half)data[startIndex])); writer.Write(Half.GetBytes((Half)data[startIndex + 1])); writer.Write(Half.GetBytes((Half)data[startIndex + 2])); writer.Write(Half.GetBytes((Half)data[startIndex + 3])); } } } } else { for (int i = 0; i < data.Length; ++i) { writer.Write(Half.GetBytes((Half)data[i])); } } writer.Close(); fs.Close(); buffer.Release(); }
private 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; Random.InitState(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 ComputeBuffer buffer = new ComputeBuffer(m_fourierGridSize * m_fourierGridSize, sizeof(float) * 4); buffer.SetData(spectrum01); CBUtility.WriteIntoRenderTexture(m_spectrum01, 4, buffer, World.WriteData); buffer.SetData(spectrum23); CBUtility.WriteIntoRenderTexture(m_spectrum23, 4, buffer, World.WriteData); buffer.Release(); 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_variance); m_varianceShader.Dispatch(0, m_varianceSize / 4, m_varianceSize / 4, m_varianceSize / 4); //Find the maximum value for slope variance buffer = new ComputeBuffer(m_varianceSize * m_varianceSize * m_varianceSize, sizeof(float)); CBUtility.ReadFromRenderTexture(m_variance, 1, buffer, World.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(); }