/// <summary> /// Add a new TrailPoint into the activeTrail. /// </summary> /// <param name="point"></param> /// <param name="position"></param> protected void AddPoint(TrailPoint point, Vector3 position) { if (activeTrail == null) { return; } point.position = position; point.index = activeTrail.points.Count == 0 ? 0 : activeTrail.points[activeTrail.points.Count - 1].index + 1; InitializeNewPoint(point); point.distance2Src = activeTrail.points.Count == 0 ? 0 : activeTrail.points[activeTrail.points.Count - 1].distance2Src + Vector3.Distance(activeTrail.points[activeTrail.points.Count - 1].position, position); ///Override Forward to be implemented in the future. switch (parameter.orientationType) { case TrailOrientation.LookAt: point.forwardDirection = (parameter.lookAt.position - position).normalized; break; case TrailOrientation.Local: point.forwardDirection = m_transform.forward; break; case TrailOrientation.World: point.forwardDirection = parameter.forwardOverride.normalized; break; default: break; } activeTrail.points.Add(point); }
/// <summary> /// Add a new TrailPoint into the activeTrail. /// </summary> /// <param name="point"></param> /// <param name="position"></param> protected void AddPoint(TrailPoint point, Vector3 position) { if (activeTrail == null) { return; } point.position = position; point.index = activeTrail.points.Count == 0 ? 0 : activeTrail.points[activeTrail.points.Count - 1].index + 1; InitializeNewPoint(point); point.distance2Src = activeTrail.points.Count == 0 ? 0 : activeTrail.points[activeTrail.points.Count - 1].distance2Src + Vector3.Distance(activeTrail.points[activeTrail.points.Count - 1].position, position); point.forwardDirection = GetFacing(); activeTrail.points.Add(point); }
protected override void UpdateTrail(TrailGraphics trail, float deltaTime) { if (!trail.activeSelf) { return; } int trailPointIdx = 0; for (int i = 0; i < controlPoints.Count; i++) { trail.points[trailPointIdx].position = controlPoints[i].position; trail.points[trailPointIdx].forwardDirection = controlPoints[i].forward; trailPointIdx++; if (i < controlPoints.Count - 1) { Vector3 cp1, cp2; float distance = Vector3.Distance(controlPoints[i].position, controlPoints[i + 1].position) / 2; if (i == 0) { cp1 = controlPoints[i].position + (controlPoints[i + 1].position - controlPoints[i].position).normalized * distance; } else { cp1 = controlPoints[i].position + (controlPoints[i + 1].position - controlPoints[i - 1].position).normalized * distance; } int nextIdx = i + 1; if (nextIdx == controlPoints.Count - 1) { cp2 = controlPoints[nextIdx].position + (controlPoints[nextIdx - 1].position - controlPoints[nextIdx].position).normalized * distance; } else { cp2 = controlPoints[nextIdx].position + (controlPoints[nextIdx - 1].position - controlPoints[nextIdx + 1].position).normalized * distance; } TrailPoint current = trail.points[trailPointIdx - 1]; TrailPoint next = trail.points[trailPointIdx + pointsInMiddle]; for (int j = 0; j < pointsInMiddle; j++) { float t = (((float)j + 1) / ((float)pointsInMiddle + 1)); trail.points[trailPointIdx].position = Bezier.CalculateCubic(t, controlPoints[i].position, cp1, cp2, controlPoints[i + 1].position); trail.points[trailPointIdx].timeSoFar = Mathf.Lerp(current.timeSoFar, next.timeSoFar, t); trail.points[trailPointIdx].forwardDirection = Vector3.Lerp(current.forwardDirection, next.forwardDirection, t); trailPointIdx++; } } } int lastCPIdx = (pointsInMiddle + 1) * (controlPoints.Count - 1); int prevCPIdx = lastCPIdx - pointsInMiddle - 1; int activeCount = lastCPIdx + 1; float distance2Src = trail.points[prevCPIdx].distance2Src; for (int i = prevCPIdx + 1; i < activeCount; i++) { distance2Src += Vector3.Distance(trail.points[i - 1].position, trail.points[i].position); trail.points[i].distance2Src = distance2Src; } }
/// <summary> /// Help a trail generate its own Mesh. /// </summary> /// <param name="trail"></param> private void GenerateMesh(TrailGraphics trail) { trail.mesh.Clear(false); Vector3 cameraForward = Camera.main.transform.forward; ///Determine the trail forward direction. switch (parameter.orientationType) { case TrailOrientation.LookAt: cameraForward = (parameter.lookAt.position - m_transform.position).normalized; break; case TrailOrientation.Local: cameraForward = m_transform.forward; break; case TrailOrientation.World: cameraForward = parameter.forwardOverride.normalized; break; default: break; } trail.activeCount = ActivePointsNumber(trail); ///No way to draw a Mesh with only 2 vertices or even less. Exit. if (trail.activeCount < 2) { return; } int vertIdx = 0; for (int i = 0; i < trail.points.Count; i++) { TrailPoint tp = trail.points[i]; float timeFraction = tp.timeSoFar / parameter.lifeTime; if (timeFraction > 1) { continue; } if (parameter.orientationType == TrailOrientation.Local) { cameraForward = tp.forwardDirection; } Vector3 cross = Vector3.zero; if (i < trail.points.Count - 1) { cross = Vector3.Cross((trail.points[i + 1].position - tp.position).normalized, cameraForward).normalized; } else { cross = Vector3.Cross((tp.position - trail.points[i - 1].position).normalized, cameraForward).normalized; } Color c = parameter.colorOverLife.Evaluate(1 - (float)vertIdx / (float)trail.activeCount / 2f); float s = parameter.sizeOverLife.Evaluate(timeFraction); trail.vertices[vertIdx] = tp.position + cross * s; trail.uvs[vertIdx] = new Vector2(tp.distance2Src / parameter.quadScaleFactor, 0.0f); trail.normals[vertIdx] = cameraForward; trail.colors[vertIdx] = c; vertIdx++; trail.vertices[vertIdx] = tp.position - cross * s; trail.uvs[vertIdx] = new Vector2(tp.distance2Src / parameter.quadScaleFactor, 1.0f); trail.normals[vertIdx] = cameraForward; trail.colors[vertIdx] = c; vertIdx++; } ///"Stack" all redundant vertices into the termination position. Vector2 termination = trail.vertices[vertIdx - 1]; for (int i = vertIdx; i < trail.vertices.Length; i++) { trail.vertices[i] = termination; } ///Now let's focus on triangle array ... int triIdx = 0; for (int i = 0, imax = 2 * (trail.activeCount - 1); i < imax; i++) { ///Ok, start point. if (i % 2 == 0) { trail.indices[triIdx++] = i; trail.indices[triIdx++] = i + 1; trail.indices[triIdx++] = i + 2; } else ///Reverse the process. { trail.indices[triIdx++] = i + 2; trail.indices[triIdx++] = i + 1; trail.indices[triIdx++] = i; } } ///"Squash" all the redundant vertices and triangle arrays. int termIdx = trail.indices[triIdx - 1]; for (int i = triIdx; i < trail.indices.Length; i++) { trail.indices[i] = termIdx; } ///So now comes the Exciting part. CONG! trail.mesh.vertices = trail.vertices; ///Setting Indices array directly to mesh also works. trail.mesh.SetIndices(trail.indices, MeshTopology.Triangles, 0); trail.mesh.uv = trail.uvs; trail.mesh.normals = trail.normals; trail.mesh.colors = trail.colors; }
protected virtual void UpdatePoint(TrailPoint point, float deltaTime) { }
protected virtual void InitializeNewPoint(TrailPoint point) { }
/// <summary> /// Help a trail generate its own Mesh. /// </summary> /// <param name="trail"></param> private void GenerateMesh(TrailGraphics trail) { trail.mesh.Clear(false); Vector3 cameraForward = GetFacing(); trail.activeCount = ActivePointsNumber(trail); /// No way to draw a Mesh with only 2 vertices or even less. Exit. if (trail.activeCount < 2) { return; } int vertIdx = 0; Vector3 lastCross = cameraForward; if (parameter.trailType == TrailType.Vertical || parameter.isCross) { for (int i = 0; i < trail.points.Count; i++) { TrailPoint tp = trail.points[i]; float timeFraction = tp.timeSoFar / parameter.lifeTime; if (timeFraction > 1) { continue; } if (parameter.orientationType == TrailOrientation.Local) { cameraForward = tp.forwardDirection; } Vector3 cross = Vector3.zero; Vector3 moveDir = cameraForward; if (i < trail.points.Count - 1) { moveDir = (trail.points[i + 1].position - tp.position).normalized; } else { moveDir = (tp.position - trail.points[i - 1].position).normalized; } cross = Vector3.Cross(moveDir, cameraForward).normalized; if (cross.magnitude < 0.9f) { cross = lastCross.normalized; } else if (Vector3.Dot(cross, lastCross) < 0f) { cross = -cross; lastCross = -cross; } else { lastCross = cross; } Color c = parameter.colorOverLife.Evaluate(1 - (float)vertIdx / (float)trail.activeCount / 2f); float s = parameter.sizeOverLife.Evaluate(timeFraction); float uvx = parameter.isTile ? tp.distance2Src / parameter.quadScaleFactor : 1 - timeFraction; Vector3 offset = cross * s * parameter.sizeMultiplier; trail.vertices[vertIdx] = tp.position + offset; trail.uvs[vertIdx] = new Vector2(uvx, 0.0f); trail.normals[vertIdx] = cameraForward; trail.colors[vertIdx] = c; vertIdx++; trail.vertices[vertIdx] = tp.position - offset; trail.uvs[vertIdx] = new Vector2(uvx, 1.0f); trail.normals[vertIdx] = cameraForward; trail.colors[vertIdx] = c; vertIdx++; } } int oldVertIdx = vertIdx; lastCross = cameraForward; if (parameter.trailType == TrailType.Horizontal || parameter.isCross) { for (int i = 0; i < trail.points.Count; i++) { TrailPoint tp = trail.points[i]; float timeFraction = tp.timeSoFar / parameter.lifeTime; if (timeFraction > 1) { continue; } if (parameter.orientationType == TrailOrientation.Local) { cameraForward = tp.forwardDirection; } Vector3 cross = cameraForward; Color c = parameter.colorOverLife.Evaluate(1 - ((float)vertIdx - oldVertIdx) / (float)trail.activeCount / 2f); float s = parameter.sizeOverLife.Evaluate(timeFraction); float uvx = parameter.isTile ? tp.distance2Src / parameter.quadScaleFactor : 1 - timeFraction; Vector3 offset = cross * s * parameter.sizeMultiplier; trail.vertices[vertIdx] = tp.position + offset; trail.uvs[vertIdx] = new Vector2(uvx, 0.0f); trail.normals[vertIdx] = cameraForward; trail.colors[vertIdx] = c; vertIdx++; trail.vertices[vertIdx] = tp.position - offset; trail.uvs[vertIdx] = new Vector2(uvx, 1.0f); trail.normals[vertIdx] = cameraForward; trail.colors[vertIdx] = c; vertIdx++; } } /// "Stack" all redundant vertices into the termination position. Vector3 termination = trail.vertices[vertIdx - 1]; for (int i = vertIdx; i < trail.vertices.Length; i++) { trail.vertices[i] = termination; } /// Now let's focus on triangle array ... int triIdx = 0; for (int i = 0, imax = 2 * (trail.activeCount - 1); i < imax; i++) { /// Ok, start point. if (i % 2 == 0) { trail.indices[triIdx++] = i; trail.indices[triIdx++] = i + 1; trail.indices[triIdx++] = i + 2; } else /// Reverse the process. { trail.indices[triIdx++] = i + 2; trail.indices[triIdx++] = i + 1; trail.indices[triIdx++] = i; } } if (parameter.isCross) { for (int i = 2 * trail.activeCount, imax = 4 * trail.activeCount - 2; i < imax; i++) { if (i % 2 == 0) { trail.indices[triIdx++] = i; trail.indices[triIdx++] = i + 1; trail.indices[triIdx++] = i + 2; } else { trail.indices[triIdx++] = i + 2; trail.indices[triIdx++] = i + 1; trail.indices[triIdx++] = i; } } } /// "Squash" all the redundant vertices and triangle arrays. int termIdx = trail.indices[triIdx - 1]; for (int i = triIdx; i < trail.indices.Length; i++) { trail.indices[i] = termIdx; } /// So now comes the Exciting part. CONG! trail.mesh.vertices = trail.vertices; /// Setting Indices array directly to mesh also works. trail.mesh.SetIndices(trail.indices, MeshTopology.Triangles, 0); trail.mesh.uv = trail.uvs; trail.mesh.normals = trail.normals; trail.mesh.colors = trail.colors; }