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();
        }
        /*
         * Updates the ground height below camera.
         */
        void UpdateGroundHeight()
        {
            Vector3d2 localCamPos = GetTerrainNode().GetLocalCameraPos();

            //If camera has moved update ground height
            if ((localCamPos - m_oldLocalCamera).Magnitude() > 1.0 && m_cameraQuad != null && m_cameraQuad.tile != null)
            {
                GPUTileStorage.GPUSlot slot = m_cameraQuad.tile.GetSlot()[0] as GPUTileStorage.GPUSlot;

                if (slot != null)
                {
                    int border   = GetProducer().GetBorder();
                    int tileSize = GetProducer().GetTileSizeMinBorder(0);

                    float dx = m_cameraQuadCoords.x * tileSize;
                    float dy = m_cameraQuadCoords.y * tileSize;

                    //x,y are the non-normalized position in the elevations texture where the
                    //ground height below the camera is.
                    float x = dx + (float)border;
                    float y = dy + (float)border;
                    //Read the single value from the render texture
                    CBUtility.ReadSingleFromRenderTexture(slot.GetTexture(), x, y, 0, m_groundBuffer, m_manager.GetReadData(), true);
                    //Get single height value from buffer
                    float[] height = new float[1];
                    m_groundBuffer.GetData(height);

                    //Update the ground height. Stored as a static value in the TerrainNode script
                    GetView().SetGroundHeight(Math.Max(0.0, height[0]));

                    m_oldLocalCamera.x = localCamPos.x;
                    m_oldLocalCamera.y = localCamPos.y;
                    m_oldLocalCamera.z = localCamPos.z;
                }
            }

            m_cameraQuad = null;
        }
Beispiel #4
0
        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();
            }
        }