static public void Tick(World world, World.State state, World.State nextState) { _ProfileWindTick.Begin(); float inverseFullIceCoverage = 1.0f / world.Data.FullIceCoverage; for (int y = 0; y < world.Size; y++) { float latitude = world.Data.windInfo[y].latitude; var windInfo = world.Data.windInfo[y]; for (int x = 0; x < world.Size; x++) { int index = world.GetIndex(x, y); float upperPressure = state.UpperAirPressure[index]; float lowerPressure = state.LowerAirPressure[index]; float upperTemperature = state.UpperAirTemperature[index]; float lowerTemperature = state.LowerAirTemperature[index]; float elevation = state.Elevation[index]; float waterDepth = state.WaterDepth[index]; float waterAndIceDepth = state.WaterAndIceDepth[index]; float elevationOrSeaLevel = elevation + waterAndIceDepth; var normal = state.Normal[index]; float iceCoverage = state.IceMass[index] * inverseFullIceCoverage; float friction; if (waterDepth > 0) { friction = world.Data.WindOceanFriction; } else { friction = world.Data.WindLandFriction; } friction = Mathf.Clamp01(Mathf.Lerp(friction, world.Data.WindIceFriction, iceCoverage)); float lowerTemperatureAtSeaLevel = lowerTemperature - world.Data.TemperatureLapseRate * elevationOrSeaLevel; float molarMassLowerAir = Atmosphere.GetMolarMassAir(world, state.LowerAirMass[index], state.Humidity[index]); float molarMassUpperAir = Atmosphere.GetMolarMassAir(world, state.UpperAirMass[index] + state.StratosphereMass, state.CloudMass[index]); float surfaceAirDensity = Atmosphere.GetAirDensity(world, lowerPressure, lowerTemperatureAtSeaLevel, molarMassLowerAir); float boundaryElevation = elevationOrSeaLevel + world.Data.BoundaryZoneElevation; float upperTemperatureAtSeaLevel = upperTemperature - world.Data.TemperatureLapseRate * boundaryElevation; float tropopausePressure = upperPressure * Mathf.Pow(1 + world.Data.TemperatureLapseRate / upperTemperatureAtSeaLevel * world.Data.TropopauseElevation, -world.Data.PressureExponent * molarMassUpperAir); float tropopauseDensity = Atmosphere.GetAirDensity(world, tropopausePressure, upperTemperature + world.Data.TemperatureLapseRate * (world.Data.TropopauseElevation - boundaryElevation), molarMassUpperAir); var upperWindH = GetHorizontalWind(world, state, x, y, state.UpperWind[index], latitude, state.PlanetRotationSpeed, windInfo.coriolisParam, windInfo.inverseCoriolisParam, world.Data.GlobalCoriolisInfluenceWindUpper, state.UpperAirPressure, state.UpperAirTemperature, true, tropopausePressure, elevationOrSeaLevel, world.Data.TropopauseElevation, 0, tropopauseDensity, molarMassUpperAir); var lowerWindH = GetHorizontalWind(world, state, x, y, state.LowerWind[index], latitude, state.PlanetRotationSpeed, windInfo.coriolisParam, windInfo.inverseCoriolisParam, world.Data.GlobalCoriolisInfluenceWindLower, state.LowerAirPressure, state.LowerAirTemperature, false, lowerPressure, elevationOrSeaLevel, elevationOrSeaLevel, friction, surfaceAirDensity, molarMassLowerAir); // within 1 km of the ground, frictional forces slow wind down float neighborPressureDifferential = 0; float neighborElevationDifferential = 0; if (lowerWindH.x < 0) { int neighborIndex = world.GetNeighborIndex(x, y, 0); neighborPressureDifferential += -lowerWindH.x * (lowerPressure - state.LowerAirPressure[neighborIndex]); neighborElevationDifferential += -lowerWindH.x * (state.Elevation[neighborIndex] + state.WaterAndIceDepth[neighborIndex] - elevationOrSeaLevel); } else { var neighborIndex = world.GetNeighborIndex(x, y, 1); neighborPressureDifferential += lowerWindH.x * (lowerPressure - state.LowerAirPressure[neighborIndex]); neighborElevationDifferential += lowerWindH.x * (state.Elevation[neighborIndex] + state.WaterAndIceDepth[neighborIndex] - elevationOrSeaLevel); } if (lowerWindH.y < 0) { var neighborIndex = world.GetNeighborIndex(x, y, 3); neighborPressureDifferential += -lowerWindH.y * (lowerPressure - state.LowerAirPressure[neighborIndex]); neighborElevationDifferential += -lowerWindH.y * (state.Elevation[neighborIndex] + state.WaterAndIceDepth[neighborIndex] - elevationOrSeaLevel); } else { var neighborIndex = world.GetNeighborIndex(x, y, 2); neighborPressureDifferential += lowerWindH.y * (lowerPressure - state.LowerAirPressure[neighborIndex]); neighborElevationDifferential += lowerWindH.y * (state.Elevation[neighborIndex] + state.WaterAndIceDepth[neighborIndex] - elevationOrSeaLevel); } var verticalTemperatureDifferential = lowerTemperatureAtSeaLevel - upperTemperatureAtSeaLevel; float lowerWindSpeedH = lowerWindH.magnitude; float lowerWindV = neighborElevationDifferential * world.Data.MountainUpdraftWindSpeed; lowerWindV += neighborPressureDifferential * world.Data.DestinationPressureDifferentialToVerticalWindSpeed; // thermal lowerWindV += (lowerPressure - upperPressure) * world.Data.PressureToVerticalWindSpeed; // thermal nextState.LowerWind[index] = new Vector3(lowerWindH.x, lowerWindH.y, lowerWindV); nextState.UpperWind[index] = new Vector3(upperWindH.x, upperWindH.y, 0); if (float.IsNaN(nextState.UpperWind[index].x) || float.IsNaN(nextState.LowerWind[index].x) || float.IsNaN(nextState.LowerWind[index].z)) { Debug.DebugBreak(); } if (world.IsOcean(state.WaterDepth[index])) { Vector2 densityDifferential = Vector2.zero; Vector2 shallowCurrentH; float shallowCurrentV = 0; if (iceCoverage < 1) { shallowCurrentH = GetCurrentHorizontal(world, x, y, latitude, state.PlanetRotationSpeed, windInfo.coriolisParam, windInfo.inverseCoriolisParam, lowerWindH); if (iceCoverage > 0) { shallowCurrentH *= 1.0f - iceCoverage; } } else { shallowCurrentH = Vector2.zero; } if (state.DeepWaterMass[index] > 0) { float density = state.DeepWaterDensity[index]; for (int i = 0; i < 4; i++) { var neighbor = world.GetNeighbor(x, y, i); int nIndex = world.GetIndex(neighbor.x, neighbor.y); if (state.DeepWaterMass[nIndex] > 0) { //var neighborWind = state.Wind[nIndex]; //nWind += neighborWind; switch (i) { case 0: densityDifferential.x += state.DeepWaterDensity[nIndex] - density; break; case 1: densityDifferential.x -= state.DeepWaterDensity[nIndex] - density; break; case 2: densityDifferential.y -= state.DeepWaterDensity[nIndex] - density; break; case 3: densityDifferential.y += state.DeepWaterDensity[nIndex] - density; break; } } else { //switch (i) //{ // case 0: // shallowCurrentV += shallowCurrentH.x; // if (shallowCurrentH.x < 0) // { // shallowCurrentH.x = 0; // } // break; // case 1: // shallowCurrentV -= shallowCurrentH.x; // if (shallowCurrentH.x > 0) // { // shallowCurrentH.x = 0; // } // break; // case 2: // shallowCurrentV -= shallowCurrentH.y; // if (shallowCurrentH.y > 0) // { // shallowCurrentH.y = 0; // } // break; // case 3: // shallowCurrentV += shallowCurrentH.y; // if (shallowCurrentH.y < 0) // { // shallowCurrentH.y = 0; // } // break; //} } } } densityDifferential *= world.Data.OceanDensityCurrentSpeed; nextState.DeepWaterCurrent[index] = new Vector3(densityDifferential.x, densityDifferential.y, 0); nextState.ShallowWaterCurrent[index] = new Vector3(shallowCurrentH.x, shallowCurrentH.y, shallowCurrentV); } else { nextState.DeepWaterCurrent[index] = Vector3.zero; nextState.ShallowWaterCurrent[index] = Vector3.zero; } } } _ProfileWindTick.End(); }