/// <summary> /// Sets the position of the vertex in the line. /// </summary> public void SetPosition(int index, Vector3 position) { // Update internal data m_Positions[index] = position; // See if the data needs initializing if (Initialize()) { return; } // Otherwise, do fast setting m_MeshData.SetElementPosition(index * 2, ref m_Positions[index]); if (index < (m_Positions.Length - 1)) { m_MeshData.SetElementPipe((index * 2) + 1, ref m_Positions[index], ref m_Positions[index + 1]); } m_MeshData.SetMeshDataDirty(VRLineRendererInternals.MeshChain.MeshRefreshFlag.Positions); m_MeshNeedsRefreshing = true; }
/// <summary> /// Updates the built-in mesh data for each control point of the trail /// </summary> public void LateUpdate() { // We do the actual internal mesh updating as late as possible so nothing ends up a frame behind var deltaTime = Time.deltaTime; // We give the editor a little help with handling delta time in edit mode if (Application.isPlaying == false) { deltaTime = Time.realtimeSinceStartup - m_EditorDeltaHelper; m_EditorDeltaHelper = Time.realtimeSinceStartup; } // Get the current position of the renderer var currentPoint = transform.position; var pointDistance = (currentPoint - m_LastRecordedPoint).sqrMagnitude; // Is it more than minVertexDistance from the last position? if (pointDistance > (m_MinVertexDistance * m_MinVertexDistance)) { // In the situation we have no points, we need to record the start point as well if (m_PointIndexStart == m_PointIndexEnd) { m_Points[m_PointIndexStart] = m_LastRecordedPoint; m_PointTimes[m_PointIndexStart] = m_Time; } // Make space for a new point var newEndIndex = (m_PointIndexEnd + 1) % m_MaxTrailPoints; // In the situation that we are rendering all available vertices // We can either keep using the current point, or take the last point, depending on the user's preference if (newEndIndex != m_PointIndexStart) { m_PointIndexEnd = newEndIndex; m_PointTimes[m_PointIndexEnd] = 0; m_UsedPoints++; } else { if (m_StealLastPointWhenEmpty) { m_MeshData.SetElementSize(m_PointIndexStart * 2, 0); m_MeshData.SetElementSize((m_PointIndexStart * 2) + 1, 0); m_PointIndexStart = (m_PointIndexStart + 1) % m_MaxTrailPoints; m_PointIndexEnd = newEndIndex; m_PointTimes[m_PointIndexEnd] = 0; m_LastPointTime = m_PointTimes[m_PointIndexStart]; } } m_Points[m_PointIndexEnd] = currentPoint; // Update the last recorded point m_LastRecordedPoint = currentPoint; } // Do time processing // The end point counts up to a maximum of 'time' m_PointTimes[m_PointIndexEnd] = Mathf.Min(m_PointTimes[m_PointIndexEnd] + deltaTime, m_Time); if (m_PointIndexStart != m_PointIndexEnd) { // Run down the counter on the start point m_PointTimes[m_PointIndexStart] -= deltaTime; // If we've hit 0, this point is done for if (m_PointTimes[m_PointIndexStart] <= 0.0f) { m_MeshData.SetElementSize(m_PointIndexStart * 2, 0); m_MeshData.SetElementSize((m_PointIndexStart * 2) + 1, 0); m_PointIndexStart = (m_PointIndexStart + 1) % m_MaxTrailPoints; m_LastPointTime = m_PointTimes[m_PointIndexStart]; m_UsedPoints--; } } if (m_PointIndexStart != m_PointIndexEnd) { m_MeshNeedsRefreshing = true; m_MeshRenderer.enabled = true; } else { m_MeshNeedsRefreshing = false; m_MeshRenderer.enabled = false; } if (m_MeshNeedsRefreshing == true) { m_MeshRenderer.enabled = true; // Update first and last points position-wise var nextIndex = (m_PointIndexStart + 1) % m_MaxTrailPoints; if (m_SmoothInterpolation) { var toNextPoint = 1.0f - (m_PointTimes[m_PointIndexStart] / m_LastPointTime); var lerpPoint = Vector3.Lerp(m_Points[m_PointIndexStart], m_Points[nextIndex], toNextPoint); m_MeshData.SetElementPosition((m_PointIndexStart * 2), ref lerpPoint); m_MeshData.SetElementPipe((m_PointIndexStart * 2) + 1, ref lerpPoint, ref m_Points[nextIndex]); } else { m_MeshData.SetElementPosition((m_PointIndexStart * 2), ref m_Points[m_PointIndexStart]); m_MeshData.SetElementPipe((m_PointIndexStart * 2) + 1, ref m_Points[m_PointIndexStart], ref m_Points[nextIndex]); } var prevIndex = m_PointIndexEnd - 1; if (prevIndex < 0) { prevIndex = m_MaxTrailPoints - 1; } m_MeshData.SetElementPipe((prevIndex * 2) + 1, ref m_Points[prevIndex], ref m_Points[m_PointIndexEnd]); m_MeshData.SetElementPosition((m_PointIndexEnd * 2), ref m_Points[m_PointIndexEnd]); // Go through all points and update size and color var pointUpdateCounter = m_PointIndexStart; float pointCount = 0; var blendStep = 1.0f / m_UsedPoints; var colorValue = 1.0f; while (pointUpdateCounter != m_PointIndexEnd) { var currentBlend = blendStep * pointCount; var nextBlend = blendStep * (pointCount + 1.0f); var currentWidth = Mathf.Lerp(m_EndWidth, m_StartWidth, currentBlend); var nextWidth = Mathf.Lerp(m_EndWidth, m_StartWidth, nextBlend); m_MeshData.SetElementSize(pointUpdateCounter * 2, currentWidth); m_MeshData.SetElementSize((pointUpdateCounter * 2) + 1, currentWidth, nextWidth); var currentColor = GetLerpedColor(colorValue); var nextColor = GetLerpedColor(colorValue - blendStep); m_MeshData.SetElementColor(pointUpdateCounter * 2, ref currentColor); m_MeshData.SetElementColor((pointUpdateCounter * 2) + 1, ref currentColor, ref nextColor); pointUpdateCounter = (pointUpdateCounter + 1) % m_MaxTrailPoints; pointCount++; colorValue -= blendStep; } m_MeshData.SetElementSize((m_PointIndexEnd * 2), m_StartWidth); m_MeshData.SetElementColor((m_PointIndexEnd * 2), ref m_Colors[0]); m_MeshData.SetMeshDataDirty(VRLineRendererInternals.MeshChain.MeshRefreshFlag.All); m_MeshData.RefreshMesh(); } }