public void UpdateRenderer(List <StrokePoint> stroke, int maxChangedFromEnd) { int startIdx = Mathf.Max(0, stroke.Count - 1 - maxChangedFromEnd); int endIdx = stroke.Count - 1; for (int i = startIdx; i <= endIdx; i++) { StrokePoint strokePoint = stroke[i]; MeshPoint point = new MeshPoint(strokePoint.position); point.Normal = strokePoint.normal; point.Color = strokePoint.color; if (i > _ribbon.Points.Count - 1) { _ribbon.Add(point, strokePoint.thickness); } else { _ribbon.Points[i] = point; _ribbon.Radii[i] = strokePoint.thickness; } } _stroke = stroke; SetMeshDataFromRibbon(_mesh, _ribbon); }
private void RefreshRenderTrail() { Vector3 endPosition = _lastStrokeBuffer.GetLatest().position; for (int i = 0; i < _lastStrokeBuffer.Count; i++) { StrokePoint strokePoint = _lastStrokeBuffer.Get(i); MeshPoint point = new MeshPoint(strokePoint.position); point.Normal = strokePoint.normal; point.Color = strokePoint.color; if (i > _ribbon.Points.Count - 1) { _ribbon.Add(point, strokePoint.thickness); } else { // Offset from most recent + decay Vector3 offsetFromEndPosition = endPosition - point.Position; Vector3 targetOffset = (offsetFromEndPosition * (1 - _thicknessDecayMultiplier)); if (i > _prevDrawOffsets.Count - 1) { _prevDrawOffsets.Add(targetOffset); } point.Position = point.Position + Vector3.Slerp(_prevDrawOffsets[i], targetOffset, 0.1F); _prevDrawOffsets[i] = Vector3.Slerp(_prevDrawOffsets[i], targetOffset, 0.1F); _ribbon.Points[i] = point; // Thickness + decay int maxBufferSize = 16; //int effBufferSize = Mathf.Min(maxBufferSize, _lastStrokeBuffer.Size - 1); float thicknessCurveEvalPos = Mathf.Min(1F, (float)(_lastStrokeBuffer.Count - 1 - i) / maxBufferSize); // ([0-16]) / 8 --> 0, 1/8, 2/8, ... 1, 1, 1 float targetThickness = 0F; if (_lastStrokeBuffer.Count > 1) { targetThickness = strokePoint.thickness * previewThicknessCurve.Evaluate(thicknessCurveEvalPos) * _thicknessDecayMultiplier; } if (i > _prevDrawRadii.Count - 1) { _prevDrawRadii.Add(targetThickness); } if (_lastStrokeBuffer.Count - 1 - i < maxBufferSize) { _ribbon.Radii[i] = Mathf.Lerp(_prevDrawRadii[i], targetThickness, 0.05F); } else { _ribbon.Radii[i] = 0F; } _prevDrawRadii[i] = _ribbon.Radii[i]; } } SetMeshDataFromRibbon(_mesh, _ribbon); }
// shouldUpdateRenderers provides an optimization for updating multiple stroke points at once, // where it's more efficient to do the updating without rendering and then refreshing renderers // at the end. private void UpdateStroke(StrokePoint strokePoint, bool shouldUpdateRenderers = true) { _strokeBuffer.Add(strokePoint); _actualizedStrokeIdxBuffer.Add(-1); // Apply all filters in order on current stroke buffer. for (int i = 0; i < _strokeFilters.Count; i++) { _strokeFilters[i].Process(_strokeBuffer, _actualizedStrokeIdxBuffer); } if (_isActualizingStroke) { _actualizedStrokeIdxBuffer.SetLatest(_actualizedStrokeIdx++); // Output points from the buffer to the actualized stroke output. int offset = Mathf.Min(_outputBufferEndOffset, _strokeBuffer.Count - 1); for (int i = 0; i <= offset; i++) { int outputIdx = Mathf.Max(0, _outputBufferEndOffset - (_strokeBuffer.Count - 1)) + i; StrokePoint bufferStrokePoint = _strokeBuffer.Get(_strokeBuffer.Count - 1 - (Mathf.Min(_strokeBuffer.Count - 1, _outputBufferEndOffset) - i)); if (outputIdx > _strokeOutput.Count - 1) { _strokeOutput.Add(bufferStrokePoint); } else { _strokeOutput[outputIdx] = bufferStrokePoint; } } _outputBufferEndOffset += 1; // Refresh stroke renderers. if (shouldUpdateRenderers) { UpdateStrokeRenderers(); } } // Refresh stroke preview renderers. if (shouldUpdateRenderers) { UpdateStrokeBufferRenderers(); } }
private void ProcessAddStrokePoints(List <Vector3> points, List <float> effDeltaTimes) { if (points.Count != effDeltaTimes.Count) { Debug.LogError("[PinchStrokeProcessor] Points count must match effDeltaTimes count."); return; } _cachedStrokePoints.Clear(); for (int i = 0; i < points.Count; i++) { Vector3 point = points[i]; float effDeltaTime = effDeltaTimes[i]; bool shouldAdd = !_firstStrokePointAdded || Vector3.Distance(_lastStrokePointAdded, point) >= Mathf.Lerp(MIN_THICKNESS_MIN_SEGMENT_LENGTH, MAX_THICKNESS_MIN_SEGMENT_LENGTH, _thicknessFilter._lastNormalizedValue); _timeSinceLastAddition += effDeltaTime; if (shouldAdd) { StrokePoint strokePoint = new StrokePoint(); strokePoint.position = point; strokePoint.rotation = Quaternion.identity; strokePoint.handOrientation = _paintCursor.Rotation * Quaternion.Euler((_paintCursor.Handedness == Chirality.Left ? leftHandEulerRotation : rightHandEulerRotation)); strokePoint.deltaTime = _timeSinceLastAddition; _cachedStrokePoints.Add(strokePoint); _firstStrokePointAdded = true; _lastStrokePointAdded = strokePoint.position; _timeSinceLastAddition = 0F; } } _strokeProcessor.UpdateStroke(_cachedStrokePoints); }
public void UpdateRenderer(List <StrokePoint> stroke, int maxChangedFromEnd) { if (stroke.Count <= 1 || maxChangedFromEnd == 0) { return; } if (OnUpdateRenderer != null) { OnUpdateRenderer(stroke, maxChangedFromEnd); } int startIdx = Mathf.Max(0, (stroke.Count - 1) - maxChangedFromEnd - 1); int endIdx = stroke.Count - 1; // Lop off outdated vertices and indices. int expectedNewNumRibbons = stroke.Count - 1; int firstChangedRibbonIndex = expectedNewNumRibbons - 1 - maxChangedFromEnd; int numRibbonSegmentsOutdated = _ribbonSegments.Count - firstChangedRibbonIndex; int numVertsOutdated = 0; int numRibbonVertsAccountFor = 0; int numIndicesOutdated = 0; for (int i = 0; i < numRibbonSegmentsOutdated; i++) { if (i >= 0 && i < _ribbonSegments.Count) { numVertsOutdated += _ribbonSegments[_ribbonSegments.Count - 1 - i].NumVerts(); numRibbonVertsAccountFor++; numIndicesOutdated += _ribbonSegments[_ribbonSegments.Count - 1 - i].NumIndices(); } } for (int i = 0; i < numVertsOutdated; i++) { if (_verts.Count > 0) { _verts.RemoveAt(_verts.Count - 1); _colors.RemoveAt(_colors.Count - 1); _normals.RemoveAt(_normals.Count - 1); } } for (int i = 0; i < numIndicesOutdated; i++) { if (_indices.Count > 0) { _indices.RemoveAt(_indices.Count - 1); } } // Update Ribbon Segment representation. for (int i = startIdx; i < endIdx; i++) { // Define the current ribbon segment. StrokePoint curPoint = stroke[i]; StrokePoint nextPoint = stroke[i + 1]; Vector3 curSegmentDirection = (nextPoint.position - curPoint.position).normalized; Vector3 prevSegmentDirection = curSegmentDirection; bool hasPrevSegment = (i > 0); if (hasPrevSegment) { prevSegmentDirection = (stroke[i].position - stroke[i - 1].position).normalized; } Vector3 nextSegmentDirection = curSegmentDirection; bool hasNextSegment = (i < endIdx - 1); if (hasNextSegment) { nextSegmentDirection = (stroke[i + 2].position - stroke[i + 1].position).normalized; } bool curSegmentHasStartCap = i == 0; if (hasPrevSegment) { curSegmentHasStartCap = (Vector3.Dot(prevSegmentDirection, curSegmentDirection) < -0.8F); } Vector3 startFacing, startNormal; if (curSegmentHasStartCap) { startFacing = -curSegmentDirection; startNormal = curPoint.normal; } else { startFacing = -(prevSegmentDirection + curSegmentDirection).normalized; startNormal = (stroke[i - 1].normal + curPoint.normal).normalized; } bool curSegmentHasEndCap = i == stroke.Count - 2; if (hasNextSegment) { curSegmentHasEndCap = (Vector3.Dot(curSegmentDirection, nextSegmentDirection) < -0.8F); } Vector3 endFacing, endNormal; if (curSegmentHasEndCap) { endFacing = curSegmentDirection; endNormal = curPoint.normal; } else { endFacing = (curSegmentDirection + nextSegmentDirection).normalized; endNormal = (curPoint.normal + nextPoint.normal).normalized; } RibbonSegment curRibbonSegment = new RibbonSegment( curPoint.position, startFacing, startNormal, curPoint.thickness, nextPoint.position, endFacing, endNormal, nextPoint.thickness, curSegmentHasStartCap, curSegmentHasEndCap ); // Add or modify the constructed ribbon segment if (i > _ribbonSegments.Count - 1) { // Add a new ribbon segment definition. _ribbonSegments.Add(curRibbonSegment); } else { // Modify an existing ribbon segment definition. _ribbonSegments[i] = curRibbonSegment; } } // Construct and add new vertices and indices per RibbonSegment. for (int i = startIdx; i < endIdx; i++) { AddRibbonSegmentIndices(_ribbonSegments[i], _verts.Count, _indices); AddRibbonSegmentVerts(_ribbonSegments[i], _verts, _normals); for (int j = 0; j < _ribbonSegments[i].NumVerts(); j++) // color vertices { _colors.Add(stroke[i].color); } } _mesh.Clear(); _mesh.SetVertices(_verts); _mesh.SetTriangles(_indices, 0); _mesh.SetNormals(_normals); _mesh.SetColors(_colors); _mesh.RecalculateBounds(); _mesh.RecalculateNormals(); _mesh.UploadMeshData(false); _cachedStrokeRenderered = stroke; }
public void UpdateStroke(StrokePoint strokePoint) { UpdateStroke(strokePoint, true); }