Ejemplo n.º 1
0
        /*
         * 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;
        }
Ejemplo n.º 2
0
        /*
         * Sets the uniforms necessary to access the texture tile for
         * the given quad. The samplers producer must be using a GPUTileStorage at the first slot
         * for this function to work
         */
        void SetTile(ref RenderTexture tex, ref Vector3 coord, ref Vector3 size, int level, int tx, int ty)
        {
            if (!m_producer.IsGPUProducer())
            {
                return;
            }

            Tile t = null;
            int  b = m_producer.GetBorder();
            int  s = m_producer.GetCache().GetStorage(0).GetTileSize();

            float dx  = 0;
            float dy  = 0;
            float dd  = 1;
            float ds0 = (s / 2) * 2.0f - 2.0f * b;
            float ds  = ds0;

            while (!m_producer.HasTile(level, tx, ty))
            {
                dx    += (tx % 2) * dd;
                dy    += (ty % 2) * dd;
                dd    *= 2;
                ds    /= 2;
                level -= 1;
                tx    /= 2;
                ty    /= 2;

                if (level < 0)
                {
                    Debug.Log("Proland::TileSampler::SetTile - invalid level");
                    return;
                }
            }

            QuadTree tt = m_root;
            QuadTree tc;
            int      tl = 0;

            while (tl != level && (tc = tt.children[((tx >> (level - tl - 1)) & 1) | ((ty >> (level - tl - 1)) & 1) << 1]) != null)
            {
                tl += 1;
                tt  = tc;
            }

            while (level > tl)
            {
                dx    += (tx % 2) * dd;
                dy    += (ty % 2) * dd;
                dd    *= 2;
                ds    /= 2;
                level -= 1;
                tx    /= 2;
                ty    /= 2;
            }
            t = tt.tile;

            while (t == null)
            {
                dx    += (tx % 2) * dd;
                dy    += (ty % 2) * dd;
                dd    *= 2;
                ds    /= 2;
                level -= 1;
                tx    /= 2;
                ty    /= 2;
                tt     = tt.parent;

                if (tt == null)
                {
                    Debug.Log("Proland::TileSampler::SetTile - null tile");
                    return;
                }

                t = tt.tile;
            }

            dx = dx * ((s / 2) * 2 - 2 * b) / dd;
            dy = dy * ((s / 2) * 2 - 2 * b) / dd;

            if (t == null)
            {
                Debug.Log("Proland::TileSampler::SetTile - tile is null");
                return;
            }

            GPUTileStorage.GPUSlot gpuSlot = t.GetSlot(0) as GPUTileStorage.GPUSlot;

            if (gpuSlot == null)
            {
                Debug.Log("Proland::TileSampler::SetTile - gpuSlot is null");
                return;
            }

            float w = gpuSlot.GetTexture().width;
            float h = gpuSlot.GetTexture().height;

            Vector4 coords;

            if (s % 2 == 0)
            {
                coords = new Vector4((dx + b) / w, (dy + b) / h, 0.0f, ds / w);
            }
            else
            {
                coords = new Vector4((dx + b + 0.5f) / w, (dy + b + 0.5f) / h, 0.0f, ds / w);
            }

            tex   = gpuSlot.GetTexture();
            coord = new Vector3(coords.x, coords.y, coords.z);
            size  = new Vector3(coords.w, coords.w, (s / 2) * 2.0f - 2.0f * b);
        }
Ejemplo n.º 3
0
        /*
         * 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();
            }
        }