private void InterpolateSamples(FlowMap _inst, List <FlowPath.Sample> _samples, Vector2 _delta, FlowPath.Sample[,] _outputs) { var _transform = _inst.transform; var _offset = _inst.size * -0.5f + _delta * 0.5f; int _w = _outputs.GetUpperBound(0) + 1; int _h = _outputs.GetUpperBound(1) + 1; KdTree _kdTree = CreateKdTree(_samples); KdTree.KQueue _kqueue = new KdTree.KQueue(3); for (int _y = 0; _y < _h; ++_y) { for (int _x = 0; _x < _w; ++_x) { Vector2 _pos = _offset + Vector2.Scale(_delta, new Vector2(_x, _y)); Vector3 _worldPos = _transform.TransformPoint(new Vector3(_pos.x, 0, _pos.y)); FlowPath.Sample _outSamp = new FlowPath.Sample() { position = _worldPos, direction = Vector3.zero, }; int[] _knn = _kdTree.knearest(_kqueue, _worldPos, 3); if (_knn.Length == 3) { var _sampA = _samples[_knn[0]]; var _sampB = _samples[_knn[1]]; var _sampC = _samples[_knn[2]]; Vector3 _weights; Vector3 _dir = _sampA.direction; if (Geometry.GetBarycentricCoords(out _weights, _sampA.position, _sampB.position, _sampC.position, _worldPos)) { _dir = (_sampA.direction * _weights.x) + (_sampB.direction * _weights.y) + (_sampC.direction * _weights.z); } _outSamp.direction = _dir; } _outputs[_x, _y] = _outSamp; } } }
} // OnSceneGUI private void Bake(FlowMap _inst) { int _tw = Mathf.NextPowerOfTwo((int)_inst.resolution.x); int _th = Mathf.NextPowerOfTwo((int)_inst.resolution.y); Vector2 _delta = new Vector2(_inst.size.x / _tw, _inst.size.y / _th); List <FlowPath.Sample> _samples = _inst.GatherSamples(_delta * _inst.minimumDistance); if (_samples.Count == 0) { return; } FlowPath.Sample[,] _outputs = new FlowPath.Sample[_tw, _th]; InterpolateSamples(_inst, _samples, _delta, _outputs); Texture2D _tex = EncodeToTexture(_inst, _outputs); SaveTexture(_inst, _tex); } // Bake
public List <FlowPath.Sample> GatherSamples(Vector2 _sampleSize) { var _flowPaths = GetComponentsInChildren <FlowPath>(); var _rawSamples = new List <FlowPath.Sample>(); foreach (var _flow in _flowPaths) { if (null == _flow || !_flow) { continue; } (_flow as FlowPath).GatherSamples(_rawSamples, _sampleSize); } KdTree.Entry[] _kdEnt = new KdTree.Entry[_rawSamples.Count]; for (int _it = 0; _it < _rawSamples.Count; ++_it) { _kdEnt[_it] = new KdTree.Entry(_rawSamples[_it].position, _it); } KdTree _kdTree = new KdTree(); _kdTree.build(_kdEnt); KdTree.RQueue _rqueue = new KdTree.RQueue(); var _processed = new System.Collections.Generic.HashSet <int>(); float _range = Mathf.Min(_sampleSize.x, _sampleSize.y); var _filteredSamples = new List <FlowPath.Sample>(); for (int _it = 0; _it < _rawSamples.Count; ++_it) { if (_processed.Contains(_it)) { continue; } int[] _neighbours = _kdTree.rquery(_rqueue, _rawSamples[_it].position, _range); if (_neighbours.Length == 1) { _filteredSamples.Add(_rawSamples[_it]); _processed.Add(_it); } else { Vector3 _pos = Vector3.zero; Vector3 _dir = Vector3.zero; foreach (int _id in _neighbours) { _pos += _rawSamples[_id].position; _dir += _rawSamples[_id].direction; _processed.Add(_id); } FlowPath.Sample _samp = new FlowPath.Sample(); _samp.position = _pos * (1.0f / _neighbours.Length); _samp.direction = _dir * (1.0f / _neighbours.Length); _filteredSamples.Add(_samp); } } return(_filteredSamples); }