protected void UpdateRemoveDeadSections() { int lastDeadSectionIndex = -1; float minLiveBirthTime = Time.time - LifeTime; for (int iSection = 0; iSection < m_Sections.Count; iSection++) { hwmTrailSection iterSection = m_Sections[iSection]; if (iterSection.BirthTime > minLiveBirthTime) { lastDeadSectionIndex = iSection - 1; break; } } if (lastDeadSectionIndex > -1) // 说明有过期的Section { /* 断裂效果说明:例 * 下图第一行是Section Index 第二行中"*"是Section "----"是画出来的Trail * 0 1 2 3 4 *----*----*----*----* * 当有2个Section过期时,如果移除两个Section,结果如下图 * 2 3 4 * ----*----*----* * ↑这里断裂 * 为了避免断裂效果,我们只移除1个Section(iLastOutdateSection = 1) * 1 2 3 4 *----*----*----* */ m_Sections.RemoveRange(0, lastDeadSectionIndex + 1 == m_Sections.Count ? m_Sections.Count // 所有的都过期了,我们可以彻底移除了 : lastDeadSectionIndex); // 只要不是全部过期了就保留一个过期的Section,避免断裂效果 } }
/// <summary> /// 用于更新条带段的属性。自定制的特殊动画、过渡等逻辑请写在这个方法的重载中。(见osPlaneTrail范例中如何实现的“自定制曲线的条带颜色变化”) /// </summary> protected void UpdateSections() { for (int iSection = 0; iSection < m_Sections.Count; iSection++) { hwmTrailSection currentSection = m_Sections[iSection]; currentSection.NormalizedAge = Mathf.Clamp01((Time.time - currentSection.BirthTime) / LifeTime); currentSection.Color = Color.Lerp(StartColor, EndColor, currentSection.NormalizedAge); currentSection.HalfWidth = Mathf.Lerp(StartHalfWidth, EndHalfWidth, currentSection.NormalizedAge); } }
/// <summary> /// 计算Trail世界空间的包围球 /// 如果当前没有Section,则返回中心为发射器的位置,大小为0的Bounds /// TODO 优化计算方式,降低计算频率 /// 这种计算方式更适合处理一直朝某方向飞的条带 /// 遍历所有的Section计算Bounds太废了,又不可能实现通用且高效的算法 /// 考虑让子类重载,根据不同情况去优化计算 /// </summary> protected Bounds CaculateBounds() { Bounds bounds = new Bounds(transform.position, Vector3.zero); if (m_Sections.Count > 0) { hwmTrailSection centerSection = m_Sections[m_Sections.Count / 2]; hwmTrailSection lastSection = m_Sections[m_Sections.Count - 1]; bounds.Encapsulate(centerSection.Position); bounds.Encapsulate(lastSection.Position); } return(bounds); }
protected void UpdateAutoEmitting() { if (!m_IsEmitting || m_IsManualEmit) { return; } if (!(m_Me2CameraDistanceSqr < AutoEmittingWhenMe2CameraDistanceSqrIsLessThan && (EnableAutoEmittingWhenMeOutOfCamera || IsInRendererCamera(transform.position)))) { return; } Vector3 emitterPosition_RendererSpace = Quaternion.Inverse(m_TrailRenderer.transform.rotation) * (transform.position - m_TrailRenderer.transform.position); Quaternion emitterRotation_RendererSpace = transform.rotation * Quaternion.Inverse(m_TrailRenderer.transform.rotation); if (m_Sections.Count == 0) { // 在发射器上一帧的位置添加一个Section TryAddSection(emitterPosition_RendererSpace, emitterRotation_RendererSpace); // 在发射器当前位置添加一个Section作为HeadSection, TryAddSection(emitterPosition_RendererSpace, emitterRotation_RendererSpace); } else { #region 判断是否需要新的Section // TDOO 如果FOV不经常变动,可以把这个结果Cache下来。或者把这个值放在相机的管理中每帧计算 float cameraHalfTanFOV = Mathf.Tan(RendererCamera.fieldOfView * 0.5f * Mathf.Deg2Rad); // 把需要发射新Section的发射器在屏幕上移动的距离换算成世界空间的距离 float minMeMoveDistanceSqr = cameraHalfTanFOV * AutoEmittingAddSectionWhenMeMoveDistanceInScreenSpaceGreaterThen; minMeMoveDistanceSqr *= minMeMoveDistanceSqr; minMeMoveDistanceSqr *= m_Me2CameraDistanceSqr; // 需要同时满足世界空间距离和屏幕空间距离 minMeMoveDistanceSqr = Mathf.Max(AutoEmittingAddSectionWhenMeMoveDistanceSqrInWorldSpcaeGreaterThen, minMeMoveDistanceSqr); bool needAddSection = (transform.position - m_Sections[m_Sections.Count - 2].Position).sqrMagnitude > minMeMoveDistanceSqr; #endregion if (needAddSection) { TryAddSection(emitterPosition_RendererSpace, emitterRotation_RendererSpace); } else { // 将HeadSection挪到发射器的位置 hwmTrailSection headSection = m_Sections[m_Sections.Count - 1]; SetupSection(headSection, emitterPosition_RendererSpace, emitterRotation_RendererSpace, m_Sections.Count - 2); } } }
/// <summary> /// 如果希望在发射新的条带段时,能够对这个新产生的段上的数据做一些特殊处理(例如随机颜色),或者对自己扩展的变量进行初始化赋值时,重载本方法 /// </summary> protected void SetupSection(hwmTrailSection section, Vector3 position, Quaternion rotation, int previousSectionIndex) { bool isHeadSection = previousSectionIndex < 0; section.Position = position; section.BirthTime = Time.time; section.RightDirection = rotation * Vector3.right; section.NormalizedAge = 0; section.HalfWidth = StartHalfWidth; section.Color = StartColor; section.TexcoordU = isHeadSection ? 0 : (position - m_Sections[previousSectionIndex].Position).magnitude * WorldToTexcoordU + m_Sections[previousSectionIndex].TexcoordU; }
/// <summary> /// 当前Section数量超过<see cref="MaxSectionCount"/>时不会添加Section /// </summary> protected hwmTrailSection TryAddSection(Vector3 position, Quaternion rotation) { // TODO 不能添加Section会导致条带发射器终止发射,暂时的解决方法是把MaxSectionCount配的很大。预计以后顶点数可以动态改变 if (m_Sections.Count == MaxSectionCount - 1) { return(null); } hwmTrailSection newSection = new hwmTrailSection(); m_Sections.Add(newSection); SetupSection(newSection, position, rotation, m_Sections.Count - 2); return(newSection); }
/// <summary> /// 用于将条带的Section转换为用于渲染的顶点、索引缓冲 /// 可以重载这个方法实现特定的填充策略,例如: /// 可断裂的条带 /// 更高性能的填充策略 /// 定向Billboard /// </summary> protected void UpdateBuffers() { // UNDONE 这里有点蒙蔽啊。懒得看了,直接问祝锐把 for (int iSection = 0; iSection < m_Sections.Count; iSection++) { hwmTrailSection iterSection = m_Sections[iSection]; // Generate vertices Vector3 vHalfWidth = iterSection.RightDirection * iterSection.HalfWidth; m_PositionBuffer[iSection * 4 + 0] = iterSection.Position - vHalfWidth; m_PositionBuffer[iSection * 4 + 1] = iterSection.Position + vHalfWidth; // fade colors out over time m_ColorBuffer[iSection * 4 + 0] = iterSection.Color; m_ColorBuffer[iSection * 4 + 1] = iterSection.Color; m_UVBuffer[iSection * 4 + 0] = new Vector2(iterSection.TexcoordU, 0); m_UVBuffer[iSection * 4 + 1] = new Vector2(iterSection.TexcoordU, 1); } for (int iSection = 0; iSection < m_Sections.Count - 1; iSection++) { hwmTrailSection iterSection = m_Sections[iSection + 1]; // TODO 就这里不懂,找祝锐 m_PositionBuffer[iSection * 4 + 2] = m_PositionBuffer[iSection * 4 + Mathf.Min(iSection, 1) * 4]; m_PositionBuffer[iSection * 4 + 3] = m_PositionBuffer[iSection * 4 + Mathf.Min(iSection, 1) * 5]; // fade colors out over time m_ColorBuffer[iSection * 4 + 2] = m_ColorBuffer[iSection * 4 + 4]; m_ColorBuffer[iSection * 4 + 3] = m_ColorBuffer[iSection * 4 + 5]; m_UVBuffer[iSection * 4 + 2] = m_UVBuffer[iSection * 4 + 4]; m_UVBuffer[iSection * 4 + 3] = m_UVBuffer[iSection * 4 + 5]; } for (int iSection = (m_Sections.Count - 1) * 4; iSection < m_PositionBuffer.Length; ++iSection) { // TODO 这里也不懂。这样为什么不会渲染出从最后一个Section到这个位置的Trail?是被裁剪掉了么。不是会把一个三角形切开,然后渲染在屏幕中的部分么。为什么全裁掉了 m_PositionBuffer[iSection] = new Vector3(0, -100000.0f, 0); } }
protected void OnDrawGizmosSelected() { if (!Application.isPlaying || !DEBUG_DrawGizmos) { return; } GUIStyle guiStyle = new GUIStyle(); guiStyle.fontSize = 15; guiStyle.normal.textColor = Color.green; for (int iSection = 0; iSection < m_Sections.Count; ++iSection) { hwmTrailSection iterSection = m_Sections[iSection]; Gizmos.color = iSection == 0 ? new Color(1.0f, 0, 0, 0.5f) : new Color(1.0f, 1.0f, 1.0f, 0.5f); float radius = Mathf.Lerp(StartHalfWidth, EndHalfWidth, iterSection.NormalizedAge); Gizmos.DrawWireSphere(iterSection.Position, radius); UnityEditor.Handles.Label(iterSection.Position, (iSection).ToString(), guiStyle); } for (int i = 0; i < m_PositionBuffer.Length; i++) { if (i % 2 == 0) { Vector3 start = m_PositionBuffer[i]; Vector3 end = m_PositionBuffer[i + 1]; Gizmos.color = Color.yellow; Gizmos.DrawLine(start, end); if (i % 4 == 0) { Gizmos.color = Color.green; guiStyle.normal.textColor = Color.green; Gizmos.DrawSphere(start, 0.05f); UnityEditor.Handles.Label(start + Vector3.right * .2f, i.ToString(), guiStyle); Gizmos.color = Color.red; guiStyle.normal.textColor = Color.red; Gizmos.DrawSphere(end, 0.05f); UnityEditor.Handles.Label(end - Vector3.right * .2f, (i + 1).ToString(), guiStyle); } else { Gizmos.color = Color.green; guiStyle.normal.textColor = Color.green; Gizmos.DrawSphere(start, 0.05f); UnityEditor.Handles.Label(start + Vector3.right * .2f + Vector3.forward * .2f, i.ToString(), guiStyle); Gizmos.color = Color.red; guiStyle.normal.textColor = Color.red; Gizmos.DrawSphere(end, 0.05f); UnityEditor.Handles.Label(end - Vector3.right * .2f + Vector3.forward * .2f, (i + 1).ToString(), guiStyle); } } } Bounds bounds = m_TrailRenderer._MeshRenderer.bounds; Gizmos.color = Color.white; Gizmos.DrawWireSphere(bounds.center, bounds.extents.magnitude); }