Пример #1
0
        /// <summary>
        /// Returns result of GPU readback of a LOD data. Do not hold onto the returned reference across frames.
        /// </summary>
        protected PerLodData GetData(Rect sampleAreaXZ, float minSpatialLength)
        {
            PerLodData lastCandidate = null;
            // This data will be returned if lastCandidate is null at the end
            PerLodData lastPossibleCandidate = null;

            for (int i = 0; i < _perLodData.KeyArray.Length; i++)
            {
                var lodData = _perLodData.ValueArray[i];
                if (!lodData._activelyBeingRendered || lodData._resultData._time == -1f)
                {
                    continue;
                }

                // Store the last lodData with valid rectangle coverage;
                lastPossibleCandidate = lodData;

                // Check that the region of interest is covered by this data
                var wdcRect = lodData._resultData._renderData.RectXZ;
                // Shrink rect by 1 texel border - this is to make finite differences fit as well
                float texelWidth = _perLodData.KeyArray[i];
                wdcRect.x     += texelWidth; wdcRect.y += texelWidth;
                wdcRect.width -= 2f * texelWidth; wdcRect.height -= 2f * texelWidth;
                if (!wdcRect.Contains(sampleAreaXZ.min) || !wdcRect.Contains(sampleAreaXZ.max))
                {
                    continue;
                }

                // This data covers our required area, so store it as a potential candidate
                lastCandidate = lodData;

                // The smallest wavelengths should repeat no more than twice across the smaller spatial length. Unless we're
                // in the last LOD - then this is the best we can do.
                float minWavelength = texelWidth * OceanRenderer.Instance.MinTexelsPerWave;
                if (minSpatialLength / minWavelength > 2f)
                {
                    continue;
                }

                // A good match - return immediately
                return(lodData);
            }

            // We didnt get a perfect match, but pick the next best candidate
            if (lastCandidate != null)
            {
                return(lastCandidate);
            }
            else
            {
                return(lastPossibleCandidate);
            }
        }
Пример #2
0
        /// <summary>
        /// Returns result of GPU readback of a LOD data. Do not hold onto the returned reference across frames.
        /// </summary>
        /// <param name="sampleAreaXZ">The area of interest, can be 0 area.</param>
        /// <param name="minSpatialLength">Min spatial length is the minimum side length that you care about. For e.g.
        /// if a boat has dimensions 3m x 2m, set this to 2, and then suitable wavelengths will be preferred.</param>
        protected PerLodData GetData(Rect sampleAreaXZ, float minSpatialLength)
        {
            PerLodData lastCandidate = null;

            foreach (var gridSize_lodData in _perLodData)
            {
                if (!gridSize_lodData.Value._activelyBeingRendered || gridSize_lodData.Value._resultData._time == -1f)
                {
                    continue;
                }

                // Check that the region of interest is covered by this data
                var wdcRect = gridSize_lodData.Value._resultData._renderData.RectXZ;
                // Shrink rect by 1 texel border - this is to make finite differences fit as well
                float texelWidth = gridSize_lodData.Key;
                wdcRect.x     += texelWidth; wdcRect.y += texelWidth;
                wdcRect.width -= 2f * texelWidth; wdcRect.height -= 2f * texelWidth;
                if (!wdcRect.Contains(sampleAreaXZ.min) || !wdcRect.Contains(sampleAreaXZ.max))
                {
                    continue;
                }

                // This data covers our required area, so store it as a potential candidate
                lastCandidate = gridSize_lodData.Value;

                // The smallest wavelengths should repeat no more than twice across the smaller spatial length. Unless we're
                // in the last LOD - then this is the best we can do.
                float minWavelength = texelWidth * OceanRenderer.Instance._minTexelsPerWave;
                if (minSpatialLength / minWavelength > 2f)
                {
                    continue;
                }

                // A good match - return immediately
                return(gridSize_lodData.Value);
            }

            // We didnt get a perfect match, but pick the next best candidate
            return(lastCandidate);
        }
Пример #3
0
 public bool PrewarmForSamplingArea(Rect areaXZ, float minSpatialLength)
 {
     return((_areaData = GetData(areaXZ, minSpatialLength)) != null);
 }
Пример #4
0
        void ProcessArrivedRequests(PerLodData lodData)
        {
            var requests = lodData._requests;

            if (!lodData._activelyBeingRendered)
            {
                // Dump all requests :/. No point processing these, and we have marked the data as being invalid and don't
                // want any new data coming in and stomping the valid flag.
                requests.Clear();
                return;
            }

            // Physics stuff may call update from FixedUpdate() - therefore check if this component was already
            // updated this frame.
            if (lodData._lastUpdateFrame == Time.frameCount)
            {
                return;
            }
            lodData._lastUpdateFrame = Time.frameCount;

            // remove any failed readback requests
            for (int i = 0; i < MAX_REQUESTS && requests.Count > 0; i++)
            {
                var request = requests.Peek();
                if (request._request.hasError)
                {
                    requests.Dequeue();
                }
                else
                {
                    break;
                }
            }

            // process current request queue
            if (requests.Count > 0)
            {
                var request = requests.Peek();
                if (request._request.done)
                {
                    requests.Dequeue();

                    // Eat up any more completed requests to squeeze out latency wherever possible
                    ReadbackRequest nextRequest;
                    while (requests.Count > 0 && (nextRequest = requests.Peek())._request.done)
                    {
                        // Has error will be true if data already destroyed and is therefore unusable
                        if (!nextRequest._request.hasError)
                        {
                            request = nextRequest;
                        }
                        requests.Dequeue();
                    }

                    UnityEngine.Profiling.Profiler.BeginSample("Copy out readback data");

                    var result     = lodData._resultData;
                    var resultLast = lodData._resultDataPrevFrame;

                    // copy result into resultLast
                    resultLast._renderData = result._renderData;
                    resultLast._time       = result._time;
                    Swap(ref result._data, ref resultLast._data);

                    // copy new data into result
                    var data = request._request.GetData <ushort>();
                    data.CopyTo(result._data);
                    result._renderData = request._renderData;
                    result._time       = request._time;

                    UnityEngine.Profiling.Profiler.EndSample();
                }
            }
        }
Пример #5
0
        void ProcessRequestsInternal(bool runningFromUpdate)
        {
            var ocean    = OceanRenderer.Instance;
            int lodCount = ocean.CurrentLodCount;

            // When viewer changes altitude, lods will start/stop updating. Mark ones that are/arent being rendered!
            for (int i = 0; i < _perLodData.KeyArray.Length; i++)
            {
                int lastUsableIndex = CanUseLastTwoLODs ? (lodCount - 1) : (lodCount - 3);

                _perLodData.ValueArray[i]._activelyBeingRendered =
                    _perLodData.KeyArray[i] >= ocean._lodTransform._renderData[0]._texelWidth &&
                    _perLodData.KeyArray[i] <= ocean._lodTransform._renderData[lastUsableIndex]._texelWidth;

                if (!_perLodData.ValueArray[i]._activelyBeingRendered)
                {
                    // It would be cleaner to destroy these. However they contain a NativeArray with a non-negligible amount of data
                    // which we don't want to alloc and dealloc willy nilly, so just mark as invalid by setting time to -1.
                    _perLodData.ValueArray[i]._resultData._time          = -1f;
                    _perLodData.ValueArray[i]._resultDataPrevFrame._time = -1f;
                }
            }

            var lt = ocean._lodTransform;

            for (int lodIndex = 0; lodIndex < ocean.CurrentLodCount; lodIndex++)
            {
                float lodTexelWidth = lt._renderData[lodIndex]._texelWidth;

                // Don't add uninitialised data
                if (lodTexelWidth == 0f)
                {
                    continue;
                }

                if (lodTexelWidth >= _minGridSize && (lodTexelWidth <= _maxGridSize || _maxGridSize == 0f))
                {
                    var tex = _lodComponent.DataTexture;
                    if (tex == null)
                    {
                        continue;
                    }

                    if (!_perLodData.ContainsKey(lodTexelWidth))
                    {
                        var resultData = new PerLodData();
                        resultData._resultData          = new ReadbackData();
                        resultData._resultDataPrevFrame = new ReadbackData();

                        // create native arrays
                        Debug.Assert(_textureFormat != TexFormat.NotSet, "ReadbackLodData: Texture format must be set.", this);
                        var num = ((int)_textureFormat) * tex.width * tex.height;
                        if (!resultData._resultData._data.IsCreated || resultData._resultData._data.Length != num)
                        {
                            resultData._resultData._data          = new NativeArray <ushort>(num, Allocator.Persistent);
                            resultData._resultDataPrevFrame._data = new NativeArray <ushort>(num, Allocator.Persistent);
                        }

                        _perLodData.Add(lodTexelWidth, resultData);
                    }

                    var lodData = _perLodData[lodTexelWidth];

                    if (lodData._activelyBeingRendered)
                    {
                        // Only enqueue new requests at beginning of update turns out to be a good time to sample the textures to
                        // ensure everything in the frame is done.
                        if (runningFromUpdate)
                        {
                            EnqueueReadbackRequest(tex, lodIndex, lt._renderData[lodIndex], _prevFrameTime);
                        }

                        ProcessArrivedRequests(lodData);
                    }
                }
            }
        }
Пример #6
0
        void ProcessRequestsInternal(bool runningFromUpdate)
        {
            // When viewer changes altitude, lods will start/stop updating. Mark ones that are/arent being rendered!
            foreach (var gridSize_lodData in _perLodData)
            {
                bool CAN_USE_LAST_LOD = false;
                int  lastUsableIndex  = CAN_USE_LAST_LOD ? (_lodComponents.Length - 1) : (_lodComponents.Length - 2);

                gridSize_lodData.Value._activelyBeingRendered =
                    gridSize_lodData.Key >= _lodComponents[0].LodTransform._renderData._texelWidth &&
                    gridSize_lodData.Key <= _lodComponents[lastUsableIndex].LodTransform._renderData._texelWidth;

                if (!gridSize_lodData.Value._activelyBeingRendered)
                {
                    // It would be cleaner to destroy these. However they contain a NativeArray with a non-negligible amount of data
                    // which we don't want to alloc and dealloc willy nilly, so just mark as invalid by setting time to -1.
                    gridSize_lodData.Value._resultData._time          = -1f;
                    gridSize_lodData.Value._resultDataPrevFrame._time = -1f;
                }
            }

            foreach (var data in _lodComponents)
            {
                var lt = data.LodTransform;
                if (lt._renderData._texelWidth >= _minGridSize && (lt._renderData._texelWidth <= _maxGridSize || _maxGridSize == 0f))
                {
                    var cam = lt.GetComponent <Camera>();

                    if (!_perLodData.ContainsKey(lt._renderData._texelWidth))
                    {
                        var resultData = new PerLodData();
                        resultData._resultData          = new ReadbackData();
                        resultData._resultDataPrevFrame = new ReadbackData();

                        // create native arrays
                        Debug.Assert(_textureFormat != TexFormat.NotSet, "ReadbackLodData: Texture format must be set.", this);
                        var num = ((int)_textureFormat) * cam.targetTexture.width * cam.targetTexture.height;
                        if (!resultData._resultData._data.IsCreated || resultData._resultData._data.Length != num)
                        {
                            resultData._resultData._data          = new NativeArray <ushort>(num, Allocator.Persistent);
                            resultData._resultDataPrevFrame._data = new NativeArray <ushort>(num, Allocator.Persistent);
                        }

                        _perLodData.Add(lt._renderData._texelWidth, resultData);
                    }

                    var lodData = _perLodData[lt._renderData._texelWidth];

                    if (lodData._activelyBeingRendered)
                    {
                        // Only enqueue new requests at beginning of update turns out to be a good time to sample the textures to
                        // ensure everything in the frame is done.
                        if (runningFromUpdate)
                        {
                            EnqueueReadbackRequest(cam.targetTexture, lt._renderData, _prevFrameTime);
                        }

                        ProcessArrivedRequests(lodData);
                    }
                }
            }
        }