Ejemplo n.º 1
0
        public void SampleDisplacementVel(ref Vector3 i_worldPos, SamplingData i_samplingData, out Vector3 o_displacement, out bool o_displacementValid, out Vector3 o_displacementVel, out bool o_velValid)
        {
            var lodData = i_samplingData._tag as PerLodData;

            o_displacementValid = lodData._resultData.InterpolateARGB16(ref i_worldPos, out o_displacement);
            if (!o_displacementValid)
            {
                o_displacementVel = Vector3.zero;
                o_velValid        = false;
                return;
            }

            // Check if this lod changed scales between result and previous result - if so can't compute vel. This should
            // probably go search for the results in the other LODs but returning 0 is easiest for now and should be ok-ish
            // for physics code.
            if (lodData._resultDataPrevFrame._renderData._texelWidth != lodData._resultData._renderData._texelWidth)
            {
                o_displacementVel = Vector3.zero;
                o_velValid        = false;
                return;
            }

            Vector3 dispLast;

            o_velValid = lodData._resultDataPrevFrame.InterpolateARGB16(ref i_worldPos, out dispLast);
            if (!o_velValid)
            {
                o_displacementVel = Vector3.zero;
                return;
            }

            Debug.Assert(lodData._resultData.Valid && lodData._resultDataPrevFrame.Valid);
            o_displacementVel = (o_displacement - dispLast) / Mathf.Max(0.0001f, lodData._resultData._time - lodData._resultDataPrevFrame._time);
        }
Ejemplo n.º 2
0
        public int Query(int i_ownerHash, SamplingData i_samplingData, Vector3[] i_queryPoints, Vector3[] o_resultDisps, Vector3[] o_resultNorms, Vector3[] o_resultVels)
        {
            if (o_resultDisps != null)
            {
                for (int i = 0; i < o_resultDisps.Length; i++)
                {
                    SampleDisplacement(ref i_queryPoints[i], i_samplingData, out o_resultDisps[i]);
                }
            }

            if (o_resultNorms != null)
            {
                for (int i = 0; i < o_resultNorms.Length; i++)
                {
                    Vector3 undispPos;
                    if (ComputeUndisplacedPosition(ref i_queryPoints[i], i_samplingData, out undispPos))
                    {
                        SampleNormal(ref undispPos, i_samplingData, out o_resultNorms[i]);
                    }
                    else
                    {
                        o_resultNorms[i] = Vector3.up;
                    }
                }
            }

            return(0);
        }
Ejemplo n.º 3
0
 public void SampleDisplacementVel(ref Vector3 i_worldPos, SamplingData i_samplingData, out Vector3 o_displacement, out bool o_displacementValid, out Vector3 o_displacementVel, out bool o_velValid)
 {
     o_displacement      = Vector3.zero;
     o_displacementValid = true;
     o_displacementVel   = Vector3.zero;
     o_velValid          = true;
 }
        public bool SampleHeight(ref Vector3 i_worldPos, SamplingData i_samplingData, out float o_height)
        {
            o_height = 0f;

            Vector3 posFlatland = i_worldPos;

            posFlatland.y = OceanRenderer.Instance.transform.position.y;

            Vector3 undisplacedPos;

            if (!ComputeUndisplacedPosition(ref posFlatland, i_samplingData, out undisplacedPos))
            {
                return(false);
            }

            Vector3 disp;

            if (!SampleDisplacement(ref undisplacedPos, i_samplingData, out disp))
            {
                return(false);
            }

            o_height = posFlatland.y + disp.y;

            return(true);
        }
Ejemplo n.º 5
0
        public bool ComputeUndisplacedPosition(ref Vector3 i_worldPos, SamplingData i_samplingData, out Vector3 undisplacedWorldPos)
        {
            // Tag should not be null if the collision source is GPU readback.
            Debug.Assert(i_samplingData._tag != null, "Invalid sampling data - LOD to sample from was unspecified.");

            var lodData = i_samplingData._tag as PerLodData;

            // FPI - guess should converge to location that displaces to the target position
            Vector3 guess = i_worldPos;
            // 2 iterations was enough to get very close when chop = 1, added 2 more which should be
            // sufficient for most applications. for high chop values or really stormy conditions there may
            // be some error here. one could also terminate iteration based on the size of the error, this is
            // worth trying but is left as future work for now.
            Vector3 disp = Vector3.zero;

            for (int i = 0; i < 4 && lodData._resultData.InterpolateARGB16(ref guess, out disp); i++)
            {
                Vector3 error = guess + disp - i_worldPos;
                guess.x -= error.x;
                guess.z -= error.z;
            }

            undisplacedWorldPos   = guess;
            undisplacedWorldPos.y = OceanRenderer.Instance.SeaLevel;

            return(true);
        }
Ejemplo n.º 6
0
        public int Query(int i_ownerHash, SamplingData i_samplingData, Vector3[] i_queryPoints, float[] o_resultHeights, Vector3[] o_resultNorms, Vector3[] o_resultVels)
        {
            if (o_resultHeights != null)
            {
                for (int i = 0; i < o_resultHeights.Length; i++)
                {
                    o_resultHeights[i] = 0f;
                }
            }

            if (o_resultNorms != null)
            {
                for (int i = 0; i < o_resultNorms.Length; i++)
                {
                    o_resultNorms[i] = Vector3.up;
                }
            }

            if (o_resultVels != null)
            {
                for (int i = 0; i < o_resultVels.Length; i++)
                {
                    o_resultVels[i] = Vector3.zero;
                }
            }

            return(0);
        }
Ejemplo n.º 7
0
        public bool SampleNormal(ref Vector3 i_undisplacedWorldPos, SamplingData i_samplingData, out Vector3 o_normal)
        {
            var lodData  = i_samplingData._tag as PerLodData;
            var gridSize = lodData._resultData._renderData._texelWidth;

            o_normal = Vector3.zero;

            var dispCenter = Vector3.zero;

            if (!lodData._resultData.InterpolateARGB16(ref i_undisplacedWorldPos, out dispCenter))
            {
                return(false);
            }

            var undisplacedWorldPosX = i_undisplacedWorldPos + Vector3.right * gridSize;
            var dispX = Vector3.zero;

            if (!lodData._resultData.InterpolateARGB16(ref undisplacedWorldPosX, out dispX))
            {
                return(false);
            }

            var undisplacedWorldPosZ = i_undisplacedWorldPos + Vector3.forward * gridSize;
            var dispZ = Vector3.zero;

            if (!lodData._resultData.InterpolateARGB16(ref undisplacedWorldPosZ, out dispZ))
            {
                return(false);
            }

            o_normal = Vector3.Cross(dispZ + Vector3.forward * gridSize - dispCenter, dispX + Vector3.right * gridSize - dispCenter).normalized;

            return(true);
        }
Ejemplo n.º 8
0
        public int Query(int i_ownerHash, SamplingData i_samplingData, Vector3[] i_queryPoints, float[] o_resultHeights, Vector3[] o_resultNorms, Vector3[] o_resultVels)
        {
            var status = 0;

            if (o_resultHeights != null)
            {
                for (int i = 0; i < o_resultHeights.Length; i++)
                {
                    if (o_resultVels == null)
                    {
                        Vector3 disp;
                        if (SampleDisplacement(ref i_queryPoints[i], i_samplingData, out disp))
                        {
                            o_resultHeights[i] = OceanRenderer.Instance.SeaLevel + disp.y;
                        }
                        else
                        {
                            status = 1 | status;
                        }
                    }
                    else
                    {
                        Vector3 disp;
                        bool    dispValid, velValid;
                        SampleDisplacementVel(ref i_queryPoints[i], i_samplingData, out disp, out dispValid, out o_resultVels[i], out velValid);
                        if (dispValid && velValid)
                        {
                            o_resultHeights[i] = OceanRenderer.Instance.SeaLevel + disp.y;
                        }
                        else
                        {
                            status = 1 | status;
                        }
                    }
                }
            }

            if (o_resultNorms != null)
            {
                for (int i = 0; i < o_resultNorms.Length; i++)
                {
                    Vector3 undispPos;
                    if (ComputeUndisplacedPosition(ref i_queryPoints[i], i_samplingData, out undispPos))
                    {
                        SampleNormal(ref undispPos, i_samplingData, out o_resultNorms[i]);
                    }
                    else
                    {
                        o_resultNorms[i] = Vector3.up;
                        status           = 1 | status;
                    }
                }
            }

            return(status);
        }
Ejemplo n.º 9
0
        public bool SampleDisplacement(ref Vector3 i_worldPos, SamplingData i_data, out Vector3 o_displacement)
        {
            var lodData = i_data._tag as PerLodData;

            if (lodData == null)
            {
                o_displacement = Vector3.zero;
                return(false);
            }
            return(lodData._resultData.InterpolateARGB16(ref i_worldPos, out o_displacement));
        }
        // Compute normal to a surface with a parameterization - equation 14 here: http://mathworld.wolfram.com/NormalVector.html
        public bool SampleNormal(ref Vector3 i_undisplacedWorldPos, SamplingData i_samplingData, out Vector3 o_normal)
        {
            o_normal = Vector3.zero;

            if (_amplitudes == null)
            {
                return(false);
            }

            var   pos           = new Vector2(i_undisplacedWorldPos.x, i_undisplacedWorldPos.z);
            float mytime        = OceanRenderer.Instance.CurrentTime;
            float windAngle     = OceanRenderer.Instance._windDirectionAngle;
            float minWaveLength = i_samplingData._minSpatialLength / 2f;

            // base rate of change of our displacement function in x and z is unit
            var delfdelx = Vector3.right;
            var delfdelz = Vector3.forward;

            for (int j = 0; j < _amplitudes.Length; j++)
            {
                if (_amplitudes[j] <= 0.001f)
                {
                    continue;
                }
                if (_wavelengths[j] < minWaveLength)
                {
                    continue;
                }

                float C = ComputeWaveSpeed(_wavelengths[j]);

                // direction
                var D = new Vector2(Mathf.Cos((windAngle + _angleDegs[j]) * Mathf.Deg2Rad), Mathf.Sin((windAngle + _angleDegs[j]) * Mathf.Deg2Rad));
                // wave number
                float k = 2f * Mathf.PI / _wavelengths[j];

                float x     = Vector2.Dot(D, pos);
                float t     = k * (x + C * mytime) + _phases[j];
                float disp  = k * -_spectrum._chop * Mathf.Cos(t);
                float dispx = D.x * disp;
                float dispz = D.y * disp;
                float dispy = -k *Mathf.Sin(t);

                delfdelx += _amplitudes[j] * new Vector3(D.x * dispx, D.x * dispy, D.y * dispx);
                delfdelz += _amplitudes[j] * new Vector3(D.x * dispz, D.y * dispy, D.y * dispz);
            }

            o_normal = Vector3.Cross(delfdelz, delfdelx).normalized;

            return(true);
        }
Ejemplo n.º 11
0
        public AvailabilityResult CheckAvailability(ref Vector3 i_worldPos, SamplingData i_samplingData)
        {
            Debug.Assert(i_samplingData._minSpatialLength >= 0f && i_samplingData._tag != null);

            var sampleAreaXZ = new Rect(i_worldPos.x, i_worldPos.z, 0f, 0f);

            bool oneWasInRect           = false;
            bool wavelengthsLargeEnough = false;

            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;
                }
                oneWasInRect = true;

                // 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 (i_samplingData._minSpatialLength / minWavelength > 2f)
                {
                    continue;
                }
                wavelengthsLargeEnough = true;

                return(AvailabilityResult.DataAvailable);
            }

            if (!oneWasInRect)
            {
                return(AvailabilityResult.NoDataAtThisPosition);
            }
            if (!wavelengthsLargeEnough)
            {
                return(AvailabilityResult.NoLODsBigEnoughToFilterOutWavelengths);
            }
            // Should not get here.
            return(AvailabilityResult.ValidationFailed);
        }
        public bool SampleFlow(ref Vector3 i_worldPos, SamplingData i_samplingData, out Vector2 flow)
        {
            var data = i_samplingData._tag as PerLodData;

            if (data == null)
            {
                if (i_samplingData._tag != null)
                {
                    Debug.LogError("Wrong kind of SamplingData provided - sampling data for e.g. collision and flow are not interchangeable.", this);
                }

                flow = Vector2.zero;
                return(false);
            }
            return(data._resultData.SampleRG16(ref i_worldPos, out flow));
        }
Ejemplo n.º 13
0
        public int Query(int i_ownerHash, SamplingData i_samplingData, Vector3[] i_queryPoints, Vector3[] o_resultDisps, Vector3[] o_resultNorms, Vector3[] o_resultVels)
        {
            var status = 0;

            if (o_resultDisps != null)
            {
                for (int i = 0; i < o_resultDisps.Length; i++)
                {
                    if (o_resultVels == null)
                    {
                        if (!SampleDisplacement(ref i_queryPoints[i], i_samplingData, out o_resultDisps[i]))
                        {
                            status = 1 | status;
                        }
                    }
                    else
                    {
                        bool dispValid, velValid;
                        SampleDisplacementVel(ref i_queryPoints[i], i_samplingData, out o_resultDisps[i], out dispValid, out o_resultVels[i], out velValid);
                        if (!dispValid || !velValid)
                        {
                            status = 1 | status;
                        }
                    }
                }
            }

            if (o_resultNorms != null)
            {
                for (int i = 0; i < o_resultNorms.Length; i++)
                {
                    Vector3 undispPos;
                    if (ComputeUndisplacedPosition(ref i_queryPoints[i], i_samplingData, out undispPos))
                    {
                        SampleNormal(ref undispPos, i_samplingData, out o_resultNorms[i]);
                    }
                    else
                    {
                        o_resultNorms[i] = Vector3.up;
                        status           = 1 | status;
                    }
                }
            }

            return(status);
        }
Ejemplo n.º 14
0
        public bool SampleHeight(ref Vector3 i_worldPos, SamplingData i_samplingData, out float height)
        {
            var posFlatland = i_worldPos;

            posFlatland.y = OceanRenderer.Instance.transform.position.y;

            Vector3 undisplacedPos;

            ComputeUndisplacedPosition(ref posFlatland, i_samplingData, out undisplacedPos);

            var disp = Vector3.zero;

            SampleDisplacement(ref undisplacedPos, i_samplingData, out disp);

            height = posFlatland.y + disp.y;
            return(true);
        }
Ejemplo n.º 15
0
        public bool SampleDisplacement(ref Vector3 i_worldPos, SamplingData i_samplingData, out Vector3 o_displacement)
        {
            o_displacement = Vector3.zero;

            if (_amplitudes == null)
            {
                return(false);
            }

            Vector2 pos           = new Vector2(i_worldPos.x, i_worldPos.z);
            float   mytime        = OceanRenderer.Instance.CurrentTime;
            float   windAngle     = _windDirectionAngle;
            float   minWavelength = i_samplingData._minSpatialLength / 2f;

            for (int j = 0; j < _amplitudes.Length; j++)
            {
                if (_amplitudes[j] <= 0.001f)
                {
                    continue;
                }
                if (_wavelengths[j] < minWavelength)
                {
                    continue;
                }

                float C = ComputeWaveSpeed(_wavelengths[j]);

                // direction
                Vector2 D = new Vector2(Mathf.Cos((windAngle + _angleDegs[j]) * Mathf.Deg2Rad), Mathf.Sin((windAngle + _angleDegs[j]) * Mathf.Deg2Rad));
                // wave number
                float k = 2f * Mathf.PI / _wavelengths[j];

                float x    = Vector2.Dot(D, pos);
                float t    = k * (x + C * mytime) + _phases[j];
                float disp = -_spectrum._chop * Mathf.Sin(t);
                // 変更
                o_displacement += _amplitudes[j] * new Vector3(
                    D.x * disp,
                    Mathf.Cos(t),
                    D.y * disp
                    );
            }

            return(true);
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Compute time derivative of the displacements by calculating difference from last query. More complicated than it would seem - results
        /// may not be available in one or both of the results, or the query locations in the array may change.
        /// </summary>
        protected int CalculateVelocities(int i_ownerHash, SamplingData i_samplingData, Vector3[] i_queryPositions, Vector3[] results)
        {
            // Need at least 2 returned results to do finite difference
            if (_queryResultsTime < 0f || _queryResultsTimeLast < 0f)
            {
                return(1);
            }

            Vector2Int segment;

            if (!_resultSegments.TryGetValue(i_ownerHash, out segment))
            {
                return((int)QueryStatus.RetrieveFailed);
            }

            Vector2Int segmentLast;

            if (!_resultSegmentsLast.TryGetValue(i_ownerHash, out segmentLast))
            {
                return((int)QueryStatus.NotEnoughDataForVels);
            }

            if ((segment.y - segment.x) != (segmentLast.y - segmentLast.x))
            {
                // Number of queries changed - can't handle that
                return((int)QueryStatus.VelocityDataInvalidated);
            }

            var dt = _queryResultsTime - _queryResultsTimeLast;

            if (dt < 0.0001f)
            {
                return((int)QueryStatus.InvalidDtForVelocity);
            }

            var count = results.Length;

            for (var i = 0; i < count; i++)
            {
                results[i] = (_queryResults[i + segment.x] - _queryResultsLast[i + segmentLast.x]) / dt;
            }

            return(0);
        }
        /// <summary>
        /// Height is the only thing that is cached right now. We could cache disps and normals too, but the height queries are heaviest.
        /// </summary>
        public bool SampleHeight(ref Vector3 i_worldPos, SamplingData i_samplingData, out float o_height)
        {
            var hash = CalcHash(ref i_worldPos);

            _cacheChecks++;
            if (_waterHeightCache.TryGetValue(hash, out o_height))
            {
                // got it from the cache!
                _cacheHits++;
                return(true);
            }

            // compute the height
            bool success = _collProvider.SampleHeight(ref i_worldPos, i_samplingData, out o_height);

            // populate cache (regardless of success for now)
            _waterHeightCache.Add(hash, o_height);

            return(success);
        }
Ejemplo n.º 18
0
        public int Query(int i_ownerHash, SamplingData i_samplingData, Vector3[] i_queryPoints, float[] o_resultHeights, Vector3[] o_resultNorms, Vector3[] o_resultVels)
        {
            var status = 0;

            if (o_resultHeights != null)
            {
                for (int i = 0; i < i_queryPoints.Length; i++)
                {
                    status = status | (SampleHeight(ref i_queryPoints[i], i_samplingData, out o_resultHeights[i]) ? 0 : 1);
                }
            }

            if (o_resultNorms != null)
            {
                // No caching for normals - go straight to source for these
                status = status | _collProvider.Query(i_ownerHash, i_samplingData, i_queryPoints, (float[])null, o_resultNorms, null);
            }

            return(status);
        }
Ejemplo n.º 19
0
        public int Query(int i_ownerHash, SamplingData i_samplingData, Vector3[] i_queryPoints, Vector3[] o_resultDisps, Vector3[] o_resultNorms, Vector3[] o_resultVels)
        {
            var result = (int)QueryStatus.OK;

            if (!UpdateQueryPoints(i_ownerHash, i_samplingData, i_queryPoints, o_resultNorms != null ? i_queryPoints : null))
            {
                result |= (int)QueryStatus.PostFailed;
            }

            if (!RetrieveResults(i_ownerHash, o_resultDisps, null, o_resultNorms))
            {
                result |= (int)QueryStatus.RetrieveFailed;
            }

            if (o_resultVels != null)
            {
                result |= CalculateVelocities(i_ownerHash, i_samplingData, i_queryPoints, o_resultVels);
            }

            return(result);
        }
        public bool ComputeUndisplacedPosition(ref Vector3 i_worldPos, SamplingData i_samplingData, out Vector3 o_undisplacedWorldPos)
        {
            // FPI - guess should converge to location that displaces to the target position
            Vector3 guess = i_worldPos;
            // 2 iterations was enough to get very close when chop = 1, added 2 more which should be
            // sufficient for most applications. for high chop values or really stormy conditions there may
            // be some error here. one could also terminate iteration based on the size of the error, this is
            // worth trying but is left as future work for now.
            Vector3 disp;

            for (int i = 0; i < 4 && SampleDisplacement(ref guess, i_samplingData, out disp); i++)
            {
                Vector3 error = guess + disp - i_worldPos;
                guess.x -= error.x;
                guess.z -= error.z;
            }

            o_undisplacedWorldPos   = guess;
            o_undisplacedWorldPos.y = OceanRenderer.Instance.SeaLevel;

            return(true);
        }
Ejemplo n.º 21
0
 public void ReturnSamplingData(SamplingData i_data)
 {
     i_data._tag = null;
 }
Ejemplo n.º 22
0
        public bool GetSamplingData(ref Rect i_displacedSamplingArea, float i_minSpatialLength, SamplingData o_samplingData)
        {
            o_samplingData._minSpatialLength = i_minSpatialLength;

            Rect undisplacedRect = new Rect(
                i_displacedSamplingArea.xMin - OceanRenderer.Instance.MaxHorizDisplacement,
                i_displacedSamplingArea.yMin - OceanRenderer.Instance.MaxHorizDisplacement,
                i_displacedSamplingArea.width + 2f * OceanRenderer.Instance.MaxHorizDisplacement,
                i_displacedSamplingArea.height + 2f * OceanRenderer.Instance.MaxHorizDisplacement
                );

            o_samplingData._tag = GetData(undisplacedRect, i_minSpatialLength);

            return(o_samplingData._tag != null);
        }
 public void SampleDisplacementVel(ref Vector3 i_worldPos, SamplingData i_samplingData, out Vector3 o_displacement, out bool o_displacementValid, out Vector3 o_displacementVel, out bool o_velValid)
 {
     o_displacementValid = SampleDisplacement(ref i_worldPos, i_samplingData, out o_displacement);
     o_velValid          = GetSurfaceVelocity(ref i_worldPos, i_samplingData, out o_displacementVel);
 }
 public bool ComputeUndisplacedPosition(ref Vector3 i_worldPos, SamplingData i_samplingData, out Vector3 undisplacedWorldPos)
 {
     return(_collProvider.ComputeUndisplacedPosition(ref i_worldPos, i_samplingData, out undisplacedWorldPos));
 }
 public AvailabilityResult CheckAvailability(ref Vector3 i_worldPos, SamplingData i_samplingData)
 {
     return(_amplitudes == null ? AvailabilityResult.NotInitialisedYet : AvailabilityResult.DataAvailable);
 }
 public void ReturnSamplingData(SamplingData i_data)
 {
     i_data._minSpatialLength = -1f;
 }
 public bool GetSamplingData(ref Rect i_displacedSamplingArea, float i_minSpatialLength, SamplingData o_samplingData)
 {
     // We're not bothered with areas as the waves are infinite, so just store the min wavelength.
     o_samplingData._minSpatialLength = i_minSpatialLength;
     return(true);
 }
 public void SampleDisplacementVel(ref Vector3 i_worldPos, SamplingData i_samplingData, out Vector3 o_displacement, out bool o_displacementValid, out Vector3 o_displacementVel, out bool o_velValid)
 {
     _collProvider.SampleDisplacementVel(ref i_worldPos, i_samplingData, out o_displacement, out o_displacementValid, out o_displacementVel, out o_velValid);
 }
 public bool SampleNormal(ref Vector3 i_undisplacedWorldPos, SamplingData i_samplingData, out Vector3 o_normal)
 {
     return(_collProvider.SampleNormal(ref i_undisplacedWorldPos, i_samplingData, out o_normal));
 }
Ejemplo n.º 30
0
        /// <summary>
        /// Takes a unique request ID and some world space XZ positions, and computes the displacement vector that lands at this position,
        /// to a good approximation. The world space height of the water at that position is then SeaLevel + displacement.y.
        /// </summary>
        protected bool UpdateQueryPoints(int i_ownerHash, SamplingData i_samplingData, Vector3[] queryPoints, Vector3[] queryNormals)
        {
            var        segmentRetrieved = false;
            Vector2Int segment;

            // We'll send in 3 points to get normals
            var countPts   = (queryPoints != null ? queryPoints.Length : 0);
            var countNorms = (queryNormals != null ? queryNormals.Length : 0);
            var countTotal = countPts + countNorms * 3;

            if (_segmentRegistrarRingBuffer.Current._segments.TryGetValue(i_ownerHash, out segment))
            {
                var segmentSize = segment.y - segment.x + 1;
                if (segmentSize == countTotal)
                {
                    segmentRetrieved = true;
                }
                else
                {
                    _segmentRegistrarRingBuffer.Current._segments.Remove(i_ownerHash);
                }
            }

            if (countTotal == 0)
            {
                // No query data
                return(false);
            }

            if (!segmentRetrieved)
            {
                if (_segmentRegistrarRingBuffer.Current._segments.Count >= s_maxGuids)
                {
                    Debug.LogError("Too many guids registered with CollProviderCompute. Increase s_maxGuids.", this);
                    return(false);
                }

                segment.x = _segmentRegistrarRingBuffer.Current._numQueries;
                segment.y = segment.x + countTotal - 1;
                _segmentRegistrarRingBuffer.Current._segments.Add(i_ownerHash, segment);

                _segmentRegistrarRingBuffer.Current._numQueries += countTotal;

                //Debug.Log("Added points for " + guid);
            }

            // 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.
            // i_samplingData._minSpatialLength
            float minWavelength = i_samplingData._minSpatialLength / 2f;
            float minGridSize   = minWavelength / OceanRenderer.Instance.MinTexelsPerWave;

            for (int pointi = 0; pointi < countPts; pointi++)
            {
                _queryPosXZ_minGridSize[pointi + segment.x].x = queryPoints[pointi].x;
                _queryPosXZ_minGridSize[pointi + segment.x].y = queryPoints[pointi].z;
                _queryPosXZ_minGridSize[pointi + segment.x].z = minGridSize;
            }

            // To compute each normal, post 3 query points
            for (int normi = 0; normi < countNorms; normi++)
            {
                var arrIdx = segment.x + countPts + 3 * normi;

                _queryPosXZ_minGridSize[arrIdx + 0].x = queryNormals[normi].x;
                _queryPosXZ_minGridSize[arrIdx + 0].y = queryNormals[normi].z;
                _queryPosXZ_minGridSize[arrIdx + 0].z = minGridSize;

                _queryPosXZ_minGridSize[arrIdx + 1].x = queryNormals[normi].x + s_finiteDiffDx;
                _queryPosXZ_minGridSize[arrIdx + 1].y = queryNormals[normi].z;
                _queryPosXZ_minGridSize[arrIdx + 1].z = minGridSize;

                _queryPosXZ_minGridSize[arrIdx + 2].x = queryNormals[normi].x;
                _queryPosXZ_minGridSize[arrIdx + 2].y = queryNormals[normi].z + s_finiteDiffDx;
                _queryPosXZ_minGridSize[arrIdx + 2].z = minGridSize;
            }

            return(true);
        }