Research:Weather
Sun glare
Actions affected | During day hours |
Description | Rendering the sun glare overlay |
Implementation status | Implemented |
Analysis status | Needs verification |
TitleCaps variables indicate values taken from the morrowind.ini section related to that object.
Glare magnitude calculation
theta = angleBetween(camera view vector, camera to sun vector) # in degrees
peakHour = Weather.SunriseHour + (Weather.SunsetHour - Weather.SunriseHour) / 2
# Angular proximity
if theta <= Weather.SunGlareFaderAngleMax:
a = 1 - theta / Weather.SunGlareFaderAngleMax
else:
a = 0
# Time of day, prevents glare interfering at sunrise/sunset
if gameHour < Weather.SunriseHour or gameHour > Weather.SunsetHour:
b = 0
elif gameHour < peakHour:
b = 1 - (peakHour - gameHour) / (peakHour - Weather.SunriseHour)
else:
b = 1 - (gameHour - peakHour) / (Weather.SunsetHour - peakHour)
b *= Weather.SunGlareFaderMax
# Specific weather variables
# transition is 0 at the start of a weather change and 1.0 at the end
# note that CloudsMaximumPercent is not actually a percentage
if weather is changing and transition < nextWeather.CloudsMaximumPercent:
t = transition / nextWeather.CloudsMaximumPercent
c = (1-t) * currentWeather.GlareView + t * nextWeather.GlareView
else:
c = currentWeather.GlareView
# Occlusion
d = time-averaged visibility of sun via raycast [range: 0-1]
Rendering
Blend mode: src=SRC_ALPHA, dest=ONE
Material colour = saturate(2 * Weather.SunGlareFaderColor) # design flaw
Material alpha = a * b * c * d
Comments
There is an issue with the colour specification. The default SunGlareFaderColor is sRGB [222,095,039], which is very red compared to the actual rendering. This is due to the game setting the ambient, diffuse and emissive materials to the SunGlareFaderColor, in combination with pure white ambient lighting for this effect (but no diffuse due to lack of normals). This essentially multiplies the colour by 2, which is then clamped by the fixed function pipeline, causing a final colour of light orange.
Wind speed
Actions affected | In all cells |
Description | Wind speed velocity vector |
Implementation status | Unknown condition |
Analysis status | Needs verification |
The game runs a simulation tick for weathers each frame. While transitioning between weathers, it simulates both the current and next weather. It stores wind velocity for both current and next weather, and interpolates between them after simulating the weathers. For interiors, wind speed is zero.
Common pre-calculation for all weathers
weatherState = weather persistent state
weatherType = simulated weather type
iniSpeed = morrowind.ini, Weather section, Wind Speed for this weather
targetSpeed = min(8.0 * iniSpeed, 70);
if currentWeather.type is weatherType:
currentSpeed = length(weatherState.windVelocityCurrentWeather)
elif nextWeather:
currentSpeed = length(weatherState.windVelocityNextWeather)
else
currentSpeed = targetSpeed
if (currentSpeed == 0)
currentSpeed = targetSpeed
Clear, Cloudy, Fog, Overcast, Snow, Blizzard
updatedSpeed = (randFloat() - 0.5) * targetSpeed + currentSpeed;
if updatedSpeed > 0.5 * targetSpeed and updatedSpeed < 2 * targetSpeed:
currentSpeed = updatedSpeed
if currentWeather.type is weatherType:
weatherState.windVelocityCurrentWeather = (0, currentSpeed, 0)
else:
weatherState.windVelocityNextWeather = (0, currentSpeed, 0)
Rain, Storm
updatedSpeed = (randFloat() - 0.5) * 0.5 * targetSpeed + currentSpeed;
if updatedSpeed > 0.5 * targetSpeed and updatedSpeed < 2 * targetSpeed:
currentSpeed = updatedSpeed
if currentWeather.type is weatherType:
weatherState.windVelocityCurrentWeather = (0, currentSpeed, 0)
else:
weatherState.windVelocityNextWeather = (0, currentSpeed, 0)
Ashstorm, Blight
stormCentre = (25000, 70000)
updatedSpeed = (randFloat() - 0.5) * targetSpeed + currentSpeed;
if updatedSpeed > 0.5 * targetSpeed and updatedSpeed < 2 * targetSpeed:
currentSpeed = updatedSpeed
if currentWeather.type is weatherType:
direction = normalize(camera.position.xy - stormCentre.xy)
weatherState.windVelocityCurrentWeather = (currentSpeed * direction.x, currentSpeed * direction.y, 0)
else:
weatherState.windVelocityNextWeather = (currentSpeed * direction.x, currentSpeed * direction.y, 0)
Comments
Final wind velocity is interpolated between weatherState.windVelocityCurrentWeather and weatherState.windVelocityNextWeather, or is zero for interiors.