private void TransformParticleSystem(ParticleSystem particles, Transform anchorTransform, float forward, float height, float rotationYModifier) { if (particles == null || !IsFirstPerson || Intensity == 0.0f) { return; } Vector3 pos = anchorTransform.position; Vector3 anchorForward; bool inNullZone = false; int count = Physics.OverlapSphereNonAlloc(anchorTransform.position, 0.001f, WeatherMakerScript.tempColliders); for (int i = 0; i < count; i++) { WeatherMakerNullZoneScript script = WeatherMakerScript.tempColliders[i].GetComponent <WeatherMakerNullZoneScript>(); if (script != null && script.NullZoneActive && (script.CurrentMask & (int)NullZoneRenderMask.Precipitation) == 0) { inNullZone = true; break; } } // update particle system state for this transform ParticleSystemState state; Dictionary <ParticleSystem, ParticleSystemState> stateDict; if (!states.TryGetValue(anchorTransform, out stateDict)) { states[anchorTransform] = stateDict = new Dictionary <ParticleSystem, ParticleSystemState>(); } if (!stateDict.TryGetValue(particles, out state)) { stateDict[particles] = state = new ParticleSystemState { PreviousPosition = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue) }; } // if we were forced to world space from local space, go back to local space if (state.WasChangedFromLocalToWorldSpace) { state.WasChangedFromLocalToWorldSpace = false; var main = particles.main; main.simulationSpace = ParticleSystemSimulationSpace.Local; } if (particles.main.simulationSpace == ParticleSystemSimulationSpace.Local && !inNullZone) { if (WeatherMakerWindScript.Instance != null && WeatherMakerWindScript.Instance.CurrentWindVelocity != Vector3.zero) { // as wind intensity increases, move forward and height of the system more inline with the player so it blows in their face anchorForward = -(WeatherMakerWindScript.Instance.CurrentWindVelocity.normalized); pos += (anchorForward * Mathf.Lerp(forward, Mathf.Max(forward, 10.0f), WeatherMakerWindScript.Instance.WindZone.windMain * 4.0f)); } else { // can't move against the transform forward because it will look awful as player rotates // just set on top of player directly anchorForward = Vector3.zero; pos.y += height; } } else { if (inNullZone) { // in null zone, put the precipitation right above the player at a distance forward = 0.0f; float standardHeight = (particles == ParticleSystem ? Height : (particles == MistParticleSystem ? MistHeight : SecondaryHeight)); height = Mathf.Max(NullZoneHeight, standardHeight); var main = particles.main; if (main.simulationSpace == ParticleSystemSimulationSpace.Local) { // mark this so we can switch back to local space when the null zone is exited state.WasChangedFromLocalToWorldSpace = true; // must use world space, looks funny swimming under water or moving in a building and moving with the player main.simulationSpace = ParticleSystemSimulationSpace.World; } } // position up and forward based on parameters anchorForward = anchorTransform.forward; pos.x += anchorForward.x * forward; pos.y += height; pos.z += anchorForward.z * forward; } // if new state or a long distance, just snap the particle system into place if (Vector3.Distance(pos, state.PreviousPosition) > 100.0f) { particles.transform.position = state.PreviousPosition = pos; } else { // go to new position quickly but not instantly particles.transform.position = state.PreviousPosition = (FirstPersonFollowSpeed <= 0.0f ? pos : Vector3.Slerp(state.PreviousPosition, pos, Time.deltaTime * FirstPersonFollowSpeed)); } if (particles.shape.mesh != null) { Vector3 angles = particles.transform.rotation.eulerAngles; particles.transform.rotation = Quaternion.Euler(angles.x, anchorTransform.rotation.eulerAngles.y * rotationYModifier, angles.z); } }
private void CameraPreCull(Camera camera) { if (!Application.isPlaying || !ShouldProcessCamera(camera)) { return; } bool intersectsCamera = false; bool hasWaterNullZone = false; if (WeatherMakerScript.IsLocalPlayer(camera.transform)) { int hits = Physics.OverlapSphereNonAlloc(camera.transform.position, 0.001f, WeatherMakerScript.tempColliders); for (int i = 0; i < hits; i++) { if (WeatherMakerScript.tempColliders[i] == waterCollider) { intersectsCamera = true; } else { WeatherMakerNullZoneScript script = WeatherMakerScript.tempColliders[i].GetComponent <WeatherMakerNullZoneScript>(); hasWaterNullZone |= (script != null && script.CurrentState != null && (script.CurrentState.RenderMask & NullZoneRenderMask.Water) != NullZoneRenderMask.Water); } } } if (intersectsCamera && !hasWaterNullZone) { if (underwaterCameras.Add(camera)) { // transition to being underwater //Debug.Log("Went underwater: " + camera.name); PlayUnderwaterSound(); PlaySplashSound(); if (UnderwaterCallback != null) { UnderwaterCallback.Invoke(this, camera, true); } // TODO: Activate any post processing volume } // render surface after precipitation and other alpha effects if under water MeshRenderer.sharedMaterial.renderQueue = 3000; isUnderwater = true; // reduce sun light as camera goes further down in the water if (WeatherMakerLightManagerScript.Instance != null) { float density = MeshRenderer.sharedMaterial.GetFloat(WMS._WaterFogDensity); float depth = Mathf.Max(0.0f, transform.position.y - camera.transform.position.y); float atten = (1.0f / (density * density * depth * depth)); atten = Mathf.Clamp(atten, 0.0f, 1.0f); WeatherMakerLightManagerScript.Instance.DirectionalLightIntensityMultipliers["WeatherMakerWaterScript" + GetInstanceID()] = atten; } } else { if (underwaterCameras.Contains(camera)) { // transition away from being underwater //Debug.Log("No longer underwater: " + camera.name); underwaterCameras.Remove(camera); if (UnderwaterAudioSource != null) { UnderwaterAudioSource.Stop(); } PlaySplashSound(); if (UnderwaterCallback != null) { UnderwaterCallback.Invoke(this, camera, false); } if (WeatherMakerLightManagerScript.Instance != null) { WeatherMakerLightManagerScript.Instance.DirectionalLightIntensityMultipliers.Remove("WeatherMakerWaterScript" + GetInstanceID()); } // TODO: Deactivate any post processing volume } #if UNITY_LWRP // can't use alpha test trick, so just render just before transparent MeshRenderer.sharedMaterial.renderQueue = 2998; #else // default render queue if above water MeshRenderer.sharedMaterial.renderQueue = -1; #endif isUnderwater = false; } }