private struct ParticleData { public ParticleSystem System; public ParticleSystem.Particle[] Particles; public Transform Camera; public ParticleSystemRenderSpace Alignment; } /// <summary> /// Collect particle systems which are in view and use billboard rendermode. /// </summary> private void PrepareParticleSystems(Transform _camera, CaptureFromCamera360 _capture) { m_lSystems.Clear(); foreach(ParticleSystem ps in GameObject.FindObjectsOfType<ParticleSystem>()) { ParticleSystemRenderer psr = ps.GetComponent<ParticleSystemRenderer>(); if (ps.isPlaying && psr.isVisible && psr.renderMode == ParticleSystemRenderMode.Billboard) { m_lSystems.Add(new ParticleData { System = ps, Particles = new ParticleSystem.Particle[ps.main.maxParticles], Camera = _camera, Alignment = psr.alignment, }); psr.alignment = ParticleSystemRenderSpace.World; } } } /// <summary> /// During video recording, manually aim all billboard particles towards cubemap camera to avoid edge artifacts. /// Algorithm is explained in this video: https://youtu.be/1hbcWhifuxE /// </summary> private void AimParticlesAtCamera() { foreach (ParticleData pd in m_lSystems) { int numParticlesAlive = pd.System.GetParticles(pd.Particles); Vector3 particleToCameraWorld = Vector3.zero; for (int i = 0; i < numParticlesAlive; i++) { Vector3 particlePosWorld = pd.System.transform.TransformPoint(pd.Particles[i].position); particleToCameraWorld = pd.Camera.position - particlePosWorld; Debug.DrawLine(particlePosWorld, particlePosWorld + Vector3.Normalize(particleToCameraWorld), Color.red); particleToCameraWorld.z *= -1.0f; pd.Particles[i].rotation3D = Quaternion.LookRotation(particleToCameraWorld, Vector3.up).eulerAngles; } pd.System.SetParticles(pd.Particles, numParticlesAlive); } } private void RestoreParticleSystems(CaptureFromCamera360 _capture) { foreach (ParticleData pd in m_lSystems) { ParticleSystemRenderer psr = pd.System.GetComponent<ParticleSystemRenderer>(); psr.alignment = pd.Alignment; } }