public BreslavTextureTransition Update(Camera cam, Transform parentObjectTransform) { var baseWeights = ComputeWeightsOfPoints(_samples, cam, parentObjectTransform); var that = this; var weights = Enumerable.Range(0, _samples.Count).Select(i => { var oldW = that._lastFrameInfo.Weights[i]; var newW = baseWeights[i]; if (oldW > 0 && newW > 0) // we only consider points that are visible in this and previous frames { return(newW); } else { return(0); } }).ToList(); var anyNotZero = weights.Any(c => c > 0); //Debug.Log(anyNotZero + ); var screenPosOfPoints = _samples.Select(c => cam.WorldToViewportPoint(parentObjectTransform.localToWorldMatrix.MultiplyPoint(c.Position))).Select(c => new Vector2(c.x, c.y)).ToList(); if (!anyNotZero) { _lastFrameInfo.Weights = baseWeights; _lastFrameInfo.SamplePointsScreenPositions = screenPosOfPoints; return(_lastTransition); } var currentCentertoid = screenPosOfPoints.Select((c, i) => c * weights[i]).Aggregate((a, b) => a + b) / weights.Sum(); var currentDeltaPositions = screenPosOfPoints.Select(c => c - currentCentertoid).ToList(); var previousCentertoid = _lastFrameInfo.SamplePointsScreenPositions.Select((c, i) => c * weights[i]).Aggregate((a, b) => a + b) / weights.Sum(); var previousDeltaPositions = _lastFrameInfo.SamplePointsScreenPositions.Select(c => c - previousCentertoid).ToList(); Vector2 z; float zScaleMultiplier = 0; if (_configuration.ZComputingMode == BreslavZComputingMode.PaperMode) { var left = Enumerable.Range(0, _samples.Count).Select(i => new Vector2( Vector2.Dot(weights[i] * previousDeltaPositions[i], currentDeltaPositions[i]), VectorUtils.CrossProduct(weights[i] * previousDeltaPositions[i], currentDeltaPositions[i]) )).Aggregate((a, b) => a + b); var right = Enumerable.Range(0, _samples.Count).Select(i => weights[i] * Math.Pow(previousDeltaPositions[i].magnitude, 2)) .Aggregate((a, b) => a + b); var _z = left / (float)right; var s = (1 / _z.magnitude) * Math.Sqrt( Enumerable.Range(0, _samples.Count).Select(i => weights[i] * Math.Pow(previousDeltaPositions[i].magnitude, 2)) .Aggregate((a, b) => a + b) / Enumerable.Range(0, _samples.Count).Select(i => weights[i] * Math.Pow(currentDeltaPositions[i].magnitude, 2)) .Aggregate((a, b) => a + b) ); if (!_configuration.DoRotation) { _z = new Vector2(_z[0], 0); } zScaleMultiplier = _z.magnitude; _z *= (float)s; z = _z; } else { double so = 0; double sn = 0; Vector2 _z = new Vector2(0, 0); for (int i = 0; i < _samples.Count; i++) { if (weights[i] > 0) { var m_o = previousDeltaPositions[i]; var m_n = currentDeltaPositions[i]; float m_w = weights[i]; _z += new Vector2((float)Cm2(m_o, m_n), (float)Det(m_o, m_n)) * m_w; so += m_o.sqrMagnitude * m_w; sn += m_n.sqrMagnitude * m_w; } } if (_configuration.DoSymmetricScalling) { _z = _z.normalized * Mathf.Sqrt((float)(sn / so)); } else { _z /= ((float)so); } zScaleMultiplier = _z.magnitude; z = _z; if (!_configuration.DoRotation) { z = new Vector2(z[0], 0); } double EPSILON = 0.00000000001; if (Math.Abs(so) <= EPSILON || Math.Abs(sn) <= EPSILON || _z.magnitude <= EPSILON) { _lastFrameInfo = new BreslavFrameInfo() { O = _lastFrameInfo.O, U = _lastFrameInfo.U, V = _lastFrameInfo.V, SamplePointsScreenPositions = screenPosOfPoints, Weights = baseWeights, LodInfo = _lastFrameInfo.LodInfo }; return(_lastTransition); } } var lodInfo = _lastFrameInfo.LodInfo.Clone(); lodInfo.Scale *= zScaleMultiplier; // interpolation parameter between 2 LOD scales float st = 0; var o = currentCentertoid + ComplexMultiplication(_lastFrameInfo.O - previousCentertoid, z); var u = ComplexMultiplication(_lastFrameInfo.U, z); var v = ComplexMultiplication(_lastFrameInfo.V, z); if (_configuration.UseLod) { float locScale = lodInfo.Scale; Preconditions.Assert(locScale > 0, $"LocScale <= 0: {locScale}"); while (locScale >= 2) //Ensuring s is [1,2) { locScale /= 2; } while (locScale < 1) { locScale *= 2; } if (locScale < _configuration.Lod_St0) { st = 0; } else if (locScale > _configuration.Lod_St1) { st = 1; } else { st = (locScale - _configuration.Lod_St0) / (_configuration.Lod_St1 - _configuration.Lod_St0); } u = u.normalized * locScale; v = v.normalized * locScale; } _lastFrameInfo = new BreslavFrameInfo() { O = o, U = u, V = v, SamplePointsScreenPositions = screenPosOfPoints, Weights = baseWeights, LodInfo = lodInfo }; return(new BreslavTextureTransition() { V = v, O = o, St = st, U = u, LodScale = lodInfo.Scale }); }