Builder Bob
Live free or don't
- Reaction score
- 249
Dynamic Ambiance
v 0.12
v 0.12
I needed a system capable of changing the fog and water tinting color dynamically depending on where the camera is looking. It turned out rather nice, so I thought I might as well share it.
To use it is very easy. All you need to do is create a region in the Region Palette, and call a function to set the fog and/or water color for that region. Everything else is handled by a running timer in-game.
If you use the GUI, follow the import instructions and look in the Trigger Editor for examples of how to make a custom script to call the functions.
It is untested in multiplayer, and I'm unable to test it myself, so I don't know how it will behave in a network.
I am unable to take screenshots because of my graphic card, but I don't think a screenshot would do the system much justice anyway.
Changes:
Changes in 0.1
- Added the function RegionRemoveAmbiance(whichRect).
- Added functionality to SetDefaultAmbiance() to allow it to be used to change the global ambiance without any existing ambiance regions in the map.
- Added check to pause the timer when no ambiance regions exist.
- Added some text commands to the test map.
- Minor fix
- Changed some code to make it compatible with newest NewGen
JASS:
// ===============================
// DynamicAmbience
// version 0.12 by Builder Bob
// ===============================
//
// Purpose
// -------
// A system for changing fog and water tinting with smooth transitions.
// Allowing you to easily create regions with specific fog and/or water tinting tied to them;
// the fog and water color will change dynamically as you move your camera around in your map.
//
// How to import
// -------------
// 1. create a trigger named DynamicAmbiance.
// 2. Edit -> Convert to Custom Text.
// 3. replace the content of that trigger with the content of this trigger.
//
// How to use
// ----------
// 1. create a region with the region palette in the Editor.
// 2. call any of the RegionSet... functions either with Jass or a custom script in GUI. (see examples)
// 3. repeat until you have enough regions.
//
// Functions
// ---------
// SetDefaultAmbiance(fogZStart, fogZEnd, fogRed, fogGreen, fogBlue, waterRed, waterGreen, waterBlue)
// sets the default ambiance in any part of the map that is not affected by ambiance regions.
//
// RegionSetAmbiance(whichRect, fogZStart, fogZEnd, fogRed, fogGreen, fogBlue, waterRed, waterGreen, waterBlue)
// sets both fog and water color for a region.
// will overwrite old values if called twice with the same input region.
//
// RegionSetFog(whichRect, fogZStart, fogZEnd, fogRed, fogGreen, fogBlue)
// sets fog color for a region. default water color will be used.
// will overwrite old values if called twice with the same input region.
//
// RegionSetWaterColor(whichRect, waterRed, waterGreen, waterBlue)
// sets water color for a region. default fog color will be used.
// will overwrite old values if called twice with the same input region.
//
// RegionRemoveAmbiance(whichRect)
// removes all ambiance set for a region.
// default fog and water color will be used until new ambiance is set.
// this function is not needed when changing the ambiance.
//
// Variable explanations
// ---------------------
// whichRect Name of your region. Regions made in the Region Palette are named gg_rct_NameOfRegion.
// fogZStart the distance from the camera the fog starts.
// fogZEnd the distance from the camera the fog ends.
// fogRed red value of the fog. (0. - 255.)
// fogGreen green value of the fog. (0. - 255.)
// fogBlue blue value of the fog. (0. - 255.)
// waterRed red value of the water. (0. - 255.)
// waterGreen green value of the water. (0. - 255.)
// waterBlue blue value of the water. (0. - 255.)
//
// Tips
// ----
// * I have used the term Ambiance for the collection of fog and water color for simplicity in this trigger.
// * Overlapping regions will give good transitions between different ambiance colors.
// * The ambiance color will never exeed the borders of it's region.
// * The ambiance color is at it's fullest value in the center of the region, and is 0 at the borders.
//
// Requires Jass NewGen Pack
// -------------------------
library DynamicAmbiance
globals
// Changeable global values
// ------------------------
// PERIOD how often the ambiance will be updated in seconds.
// CHANGE_DELAY how fast ambiance will change over time.
// AMBIANCE_STRENGTH determines the rate of dissipation for the ambiance when at the outskirts of an ambiance region.
//
// Default fog and water values can be changed here
// without the use of SetDefaultAmbiance() if prefered.
private constant real PERIOD = .04
private constant real CHANGE_DELAY = 200. * PERIOD
private constant real AMBIANCE_STRENGTH = 4.
private real DefaultFogZStart = 3000.
private real DefaultFogZEnd = 5000.
private real DefaultFogRed = 0.
private real DefaultFogGreen = 0.
private real DefaultFogBlue = 0.
private real DefaultWaterRed = 255.
private real DefaultWaterGreen = 255.
private real DefaultWaterBlue = 255.
endglobals
//SYSTEM BELOW -- Change at your own risk --
globals
private constant integer STYLE = 0
private constant real DENSITY = .00
endglobals
private function Limit takes real value, real min, real max returns real
if value < min then
set value = min
elseif value > max then
set value = max
endif
return value
endfunction
private struct AmbianceRegion
public static timer Timer = CreateTimer()
public static integer RegionCount = 0
private static real CurrentFogZStart = 3000.
private static real CurrentFogZEnd = 5000.
private static real CurrentFogRed = 0.
private static real CurrentFogGreen = 0.
private static real CurrentFogBlue = 0.
private static real CurrentWaterRed = 255.
private static real CurrentWaterGreen = 255.
private static real CurrentWaterBlue = 255.
public static region DefaultFogRegion
private boolean defaultFog = false
private boolean defaultWaterColor = false
private region ambianceRegion = CreateRegion()
private real centerX
private real centerY
private real reachX
private real reachY
private real fogZStart
private real fogZEnd
private real fogRed
private real fogGreen
private real fogBlue
private real waterRed
private real waterGreen
private real waterBlue
private static method UpdateAmbiance takes nothing returns nothing
local AmbianceRegion n = 1
local integer i
local real cameraX = GetCameraTargetPositionX()
local real cameraY = GetCameraTargetPositionY()
local real weightX
local real weightY
local real weight
local real totalWeight = 0.
local real newFogZStart = 0.
local real newFogZEnd = 0.
local real newFogRed = 0.
local real newFogGreen = 0.
local real newFogBlue = 0.
local real newWaterRed = 0.
local real newWaterGreen = 0.
local real newWaterBlue = 0.
loop
set i = n
exitwhen(i > .RegionCount)
if IsPointInRegion(n.ambianceRegion, cameraX, cameraY) then
set weightX = (cameraX - n.centerX) / n.reachX
if weightX < 0. then
set weightX = -weightX
endif
set weightX = 1. - Pow(weightX, AMBIANCE_STRENGTH)
set weightY = (cameraY - n.centerY) / n.reachY
if weightY < 0. then
set weightY = -weightY
endif
set weightY = 1. - Pow(weightY, AMBIANCE_STRENGTH)
if weightX < weightY then
set weight = weightX
else
set weight = weightY
endif
if weight < 0. then
set weight = 0.
endif
set totalWeight = totalWeight + weight
set newFogZStart = newFogZStart + weight * n.fogZStart
set newFogZEnd = newFogZEnd + weight * n.fogZEnd
set newFogRed = newFogRed + weight * n.fogRed
set newFogGreen = newFogGreen + weight * n.fogGreen
set newFogBlue = newFogBlue + weight * n.fogBlue
set newWaterRed = newWaterRed + weight * n.waterRed
set newWaterGreen = newWaterGreen + weight * n.waterGreen
set newWaterBlue = newWaterBlue + weight * n.waterBlue
endif
set n = n + 1
endloop
if totalWeight > 1. then
set newFogZStart = newFogZStart / totalWeight
set newFogZEnd = newFogZEnd / totalWeight
set newFogRed = newFogRed / totalWeight
set newFogGreen = newFogGreen / totalWeight
set newFogBlue = newFogBlue / totalWeight
set newWaterRed = newWaterRed / totalWeight
set newWaterGreen = newWaterGreen / totalWeight
set newWaterBlue = newWaterBlue / totalWeight
else
set weight = 1. - totalWeight
set newFogZStart = newFogZStart + weight * (DefaultFogZStart - newFogZStart)
set newFogZEnd = newFogZEnd + weight * (DefaultFogZEnd - newFogZEnd)
set newFogRed = newFogRed + weight * (DefaultFogRed - newFogRed)
set newFogGreen = newFogGreen + weight * (DefaultFogGreen - newFogGreen)
set newFogBlue = newFogBlue + weight * (DefaultFogBlue - newFogBlue)
set newWaterRed = newWaterRed + weight * (DefaultWaterRed - newWaterRed)
set newWaterGreen = newWaterGreen + weight * (DefaultWaterGreen - newWaterGreen)
set newWaterBlue = newWaterBlue + weight * (DefaultWaterBlue - newWaterBlue)
endif
set .CurrentFogZStart = .CurrentFogZStart + (newFogZStart - .CurrentFogZStart) / CHANGE_DELAY
set .CurrentFogZEnd = .CurrentFogZEnd + (newFogZEnd - .CurrentFogZEnd) / CHANGE_DELAY
set .CurrentFogRed = .CurrentFogRed + (newFogRed - .CurrentFogRed) / CHANGE_DELAY
set .CurrentFogGreen = .CurrentFogGreen + (newFogGreen - .CurrentFogGreen) / CHANGE_DELAY
set .CurrentFogBlue = .CurrentFogBlue + (newFogBlue - .CurrentFogBlue) / CHANGE_DELAY
set .CurrentWaterRed = .CurrentWaterRed + (newWaterRed - .CurrentWaterRed) / CHANGE_DELAY
set .CurrentWaterGreen = .CurrentWaterGreen + (newWaterGreen - .CurrentWaterGreen) / CHANGE_DELAY
set .CurrentWaterBlue = .CurrentWaterBlue + (newWaterBlue - .CurrentWaterBlue) / CHANGE_DELAY
call SetTerrainFogEx(STYLE, .CurrentFogZStart, .CurrentFogZEnd, DENSITY, .CurrentFogRed, .CurrentFogGreen, .CurrentFogBlue)
call SetWaterBaseColor(R2I(.CurrentWaterRed), R2I(.CurrentWaterGreen), R2I(.CurrentWaterBlue), 255)
if .RegionCount == 0 then
if RAbsBJ(.CurrentFogZStart - DefaultFogZStart) < .5 then
if RAbsBJ(.CurrentFogZEnd - DefaultFogZEnd) < .5 then
if RAbsBJ(.CurrentFogRed - DefaultFogRed) < .001 then
if RAbsBJ(.CurrentFogGreen - DefaultFogGreen) < .001 then
if RAbsBJ(.CurrentFogBlue - DefaultFogBlue) < .001 then
if RAbsBJ(.CurrentWaterRed - DefaultWaterRed) < .1 then
if RAbsBJ(.CurrentWaterGreen - DefaultWaterGreen) < .1 then
if RAbsBJ(.CurrentWaterBlue - DefaultWaterBlue) < .1 then
call PauseTimer(.Timer)
endif
endif
endif
endif
endif
endif
endif
endif
endif
endmethod
public static method SetDefAmb takes real fogZStart, real fogZEnd, real fogRed, real fogGreen, real fogBlue, real waterRed, real waterGreen, real waterBlue returns nothing
local AmbianceRegion n = 1
local integer i
set DefaultFogZStart = fogZStart
set DefaultFogZEnd = fogZEnd
set DefaultFogRed = Limit(fogRed / 255., 0., 1.)
set DefaultFogGreen = Limit(fogGreen / 255., 0., 1.)
set DefaultFogBlue = Limit(fogBlue / 255., 0., 1.)
set DefaultWaterRed = Limit(waterRed, 0., 255.)
set DefaultWaterGreen = Limit(waterGreen, 0., 255.)
set DefaultWaterBlue = Limit(waterBlue, 0., 255.)
loop
set i = n
exitwhen(i > .RegionCount)
if n.defaultFog then
set n.fogZStart = DefaultFogZStart
set n.fogZEnd = DefaultFogZEnd
set n.fogRed = DefaultFogRed
set n.fogGreen = DefaultFogGreen
set n.fogBlue = DefaultFogBlue
elseif n.defaultWaterColor then
set n.waterRed = DefaultWaterRed
set n.waterGreen = DefaultWaterGreen
set n.waterBlue = DefaultWaterBlue
endif
set n = n + 1
endloop
call TimerStart(.Timer, PERIOD, true, function AmbianceRegion.UpdateAmbiance)
endmethod
public static method create takes rect rc, real fogZStart, real fogZEnd, real fogRed, real fogGreen, real fogBlue, real waterRed, real waterGreen, real waterBlue, boolean defaultFog, boolean defaultWaterColor returns AmbianceRegion
local AmbianceRegion n = AmbianceRegion.allocate()
call RegionClearRect(.DefaultFogRegion, rc)
call RegionAddRect(n.ambianceRegion, rc)
set n.centerX = GetRectCenterX(rc)
set n.centerY = GetRectCenterY(rc)
set n.reachX = (GetRectMaxX(rc) - GetRectMinX(rc)) / 2.
set n.reachY = (GetRectMaxY(rc) - GetRectMinY(rc)) / 2.
set n.defaultFog = defaultFog
set n.defaultWaterColor = defaultWaterColor
set n.fogZStart = fogZStart
set n.fogZEnd = fogZEnd
set n.fogRed = Limit(fogRed / 255., 0., 1.)
set n.fogGreen = Limit(fogGreen / 255., 0., 1.)
set n.fogBlue = Limit(fogBlue / 255., 0., 1.)
set n.waterRed = Limit(waterRed, 0., 255.)
set n.waterGreen = Limit(waterGreen, 0., 255.)
set n.waterBlue = Limit(waterBlue, 0., 255.)
set .RegionCount = .RegionCount + 1
call TimerStart(.Timer, PERIOD, true, function AmbianceRegion.UpdateAmbiance)
return n
endmethod
public static method RegSetAmb takes rect rc, real fogZStart, real fogZEnd, real fogRed, real fogGreen, real fogBlue, real waterRed, real waterGreen, real waterBlue, boolean defaultFog, boolean defaultWaterColor returns nothing
local AmbianceRegion n = 1
local integer i
loop
set i = n
exitwhen(i > .RegionCount)
if GetRectCenterX(rc) == n.centerX then
if GetRectCenterY(rc) == n.centerY then
if (GetRectMaxX(rc) - GetRectMinX(rc)) / 2. == n.reachX then
if (GetRectMaxY(rc) - GetRectMinY(rc)) / 2. == n.reachY then
set n.defaultFog = defaultFog
set n.defaultWaterColor = defaultWaterColor
set n.fogZStart = fogZStart
set n.fogZEnd = fogZEnd
set n.fogRed = Limit(fogRed / 255., 0., 1.)
set n.fogGreen = Limit(fogGreen / 255., 0., 1.)
set n.fogBlue = Limit(fogBlue / 255., 0., 1.)
set n.waterRed = Limit(waterRed, 0., 255.)
set n.waterGreen = Limit(waterGreen, 0., 255.)
set n.waterBlue = Limit(waterBlue, 0., 255.)
exitwhen(true)
endif
endif
endif
endif
set n = n + 1
endloop
set i = n
if i > .RegionCount then
call AmbianceRegion.create(rc, fogZStart, fogZEnd, fogRed, fogGreen, fogBlue, waterRed, waterGreen, waterBlue, defaultFog, defaultWaterColor)
endif
endmethod
public static method RegRemAmb takes rect rc returns nothing
local AmbianceRegion n = 1
local AmbianceRegion right
local integer i
local boolean match = false
loop
set i = n
exitwhen(i > .RegionCount)
if not match then
if GetRectCenterX(rc) == n.centerX then
if GetRectCenterY(rc) == n.centerY then
if (GetRectMaxX(rc) - GetRectMinX(rc)) / 2. == n.reachX then
if (GetRectMaxY(rc) - GetRectMinY(rc)) / 2. == n.reachY then
set match = true
endif
endif
endif
endif
endif
if match then
set right = n + 1
set i = right
if i > .RegionCount then
call n.destroy()
else
set n.ambianceRegion = right.ambianceRegion
set n.centerX = right.centerX
set n.centerY = right.centerY
set n.reachX = right.reachX
set n.reachY = right.reachY
set n.defaultFog = right.defaultFog
set n.defaultWaterColor = right.defaultWaterColor
set n.fogZStart = right.fogZStart
set n.fogZEnd = right.fogZEnd
set n.fogRed = right.fogRed
set n.fogGreen = right.fogGreen
set n.fogBlue = right.fogBlue
set n.waterRed = right.waterRed
set n.waterGreen = right.waterGreen
set n.waterBlue = right.waterBlue
endif
endif
set n = n + 1
endloop
endmethod
private method onDestroy takes nothing returns nothing
call RemoveRegion(.ambianceRegion)
set .RegionCount = .RegionCount - 1
endmethod
endstruct
function SetDefaultAmbiance takes real fogZStart, real fogZEnd, real fogRed, real fogGreen, real fogBlue, real waterRed, real waterGreen, real waterBlue returns nothing
call AmbianceRegion.SetDefAmb(fogZStart, fogZEnd, fogRed, fogGreen, fogBlue, waterRed, waterGreen, waterBlue)
endfunction
function RegionSetAmbiance takes rect rc, real fogZStart, real fogZEnd, real fogRed, real fogGreen, real fogBlue, real waterRed, real waterGreen, real waterBlue returns nothing
call AmbianceRegion.RegSetAmb(rc, fogZStart, fogZEnd, fogRed, fogGreen, fogBlue, waterRed, waterGreen, waterBlue, false, false)
endfunction
function RegionSetFog takes rect rc, real fogZStart, real fogZEnd, real fogRed, real fogGreen, real fogBlue returns nothing
call AmbianceRegion.RegSetAmb(rc, fogZStart, fogZEnd, fogRed, fogGreen, fogBlue, DefaultWaterRed, DefaultWaterGreen, DefaultWaterBlue, false, true)
endfunction
function RegionSetWaterColor takes rect rc, real waterRed, real waterGreen, real waterBlue returns nothing
call AmbianceRegion.RegSetAmb(rc, DefaultFogZStart, DefaultFogZEnd, DefaultFogRed, DefaultFogGreen, DefaultFogBlue, waterRed, waterGreen, waterBlue, true, false)
endfunction
function RegionRemoveAmbiance takes rect rc returns nothing
call AmbianceRegion.RegRemAmb(rc)
endfunction
public function InitTrig takes nothing returns nothing
set AmbianceRegion.DefaultFogRegion = CreateRegion()
call RegionAddRect(AmbianceRegion.DefaultFogRegion, bj_mapInitialCameraBounds)
call SetDefaultAmbiance(DefaultFogZStart, DefaultFogZEnd, DefaultFogRed, DefaultFogGreen, DefaultFogBlue, DefaultWaterRed, DefaultWaterGreen, DefaultWaterBlue)
endfunction
endlibrary