|
function LocalToEarthTime(time) |
|
return time |
|
end |
|
|
|
function EarthToLocalTime(time) |
|
return time |
|
end |
|
|
|
g_ClassesToHideInCubemaps = { "EditorVisibleObject", "EditorEntityObject", "ShaderBall" } |
|
|
|
function SetIceStrength() end |
|
|
|
|
|
|
|
LightmodelFeatureToProperties = false |
|
|
|
|
|
local function GetFeatureValuesHash(lm, feature) |
|
local prop_ids = LightmodelFeatureToProperties[feature] |
|
if not prop_ids then return 0 end |
|
|
|
local values = {} |
|
for _, prop in ipairs(prop_ids) do |
|
values[prop.id] = lm:GetProperty(prop.id) |
|
end |
|
return table.hash(values) |
|
end |
|
|
|
function CollectUniqueParts(feature) |
|
local hash_to_lmlist = {} |
|
|
|
local preset_prop_id = "preset_" .. feature |
|
for _, lm in pairs(LightmodelPresets) do |
|
local part_id = lm:GetProperty(preset_prop_id) |
|
if not part_id or part_id == "" then |
|
local hash = GetFeatureValuesHash(lm, feature) |
|
local lm_list = hash_to_lmlist[hash] or {} |
|
table.insert(lm_list, lm.id) |
|
hash_to_lmlist[hash] = lm_list |
|
end |
|
end |
|
|
|
return hash_to_lmlist |
|
end |
|
|
|
function LightmodelEquivalenceByValue(lm, feature) |
|
local hash_to_list = CollectUniqueParts(feature) |
|
local current_hash = GetFeatureValuesHash(lm, feature) |
|
return hash_to_list[current_hash] or {} |
|
end |
|
|
|
function LightmodelFeatures() |
|
local p = {} |
|
|
|
for id in pairs(LightmodelFeatureToProperties) do |
|
if type(id) == "string" then |
|
table.insert(p, id) |
|
end |
|
end |
|
return p |
|
end |
|
|
|
DefineClass.LightmodelFeaturePreset = { |
|
__parents = {"Preset"}, |
|
PresetClass = "LightmodelFeaturePreset", |
|
properties = { |
|
{id = "Group", category = "Preset", editor = "choice", items = LightmodelFeatures, default = false, }, |
|
{category = "Diagnostics", id = "LightmodelRefs", read_only = true, dont_save = true, editor="preset_id_list", preset_class = "LightmodelPreset", default = false, }, |
|
{category = "Diagnostics", id = "EquivalentLMs", read_only = true, dont_save = true, editor="number", default = 0, buttons = { |
|
{ name = "List", func = "ListEquivalentLMs"} |
|
} }, |
|
}, |
|
EditorMenubarName = "Lightmodel features", |
|
EditorMenubar = "Editors.Art", |
|
} |
|
|
|
function LightmodelFeaturePreset:GetFeature() |
|
return self.group |
|
end |
|
|
|
function LightmodelFeaturePreset:GetProperties() |
|
local group = self.group |
|
if not group then |
|
return self.properties |
|
end |
|
local prop_ids = LightmodelFeatureToProperties[group] |
|
if not prop_ids then |
|
return self.properties |
|
end |
|
local properties = table.copy(self.properties) |
|
table.iappend(properties, prop_ids) |
|
return properties |
|
end |
|
|
|
|
|
function LightmodelFeaturePreset:GetLightmodelRefs() |
|
local ids = {} |
|
local prop_id = "preset_" .. self:GetFeature() |
|
for lm_id, lm in pairs(LightmodelPresets) do |
|
local referenced = lm:GetProperty(prop_id) |
|
if referenced == self.id then |
|
table.insert(ids, lm_id) |
|
end |
|
end |
|
return ids |
|
end |
|
|
|
function LightmodelFeaturePreset:GetEquivalentLMs() |
|
local list = LightmodelEquivalenceByValue(self, self:GetFeature()) |
|
return #list |
|
end |
|
|
|
function LightmodelFeaturePreset:ListEquivalentLMs(root, prop_id, ged, param) |
|
local list = LightmodelEquivalenceByValue(self, self:GetFeature()) |
|
ged:ShowMessage("EquivalentLMs", table.concat(list, "\n")) |
|
end |
|
|
|
function LightmodelFeaturePreset:IsLMProperty(prop_id) |
|
local prop = self:GetPropertyMetadata(prop_id) |
|
if prop and prop.feature and prop.feature == self:GetFeature() then |
|
return prop |
|
end |
|
return false |
|
end |
|
|
|
function LightmodelFeaturePreset:OnEditorSetProperty(prop_id, old_value, ged, multi) |
|
if not self:IsLMProperty(prop_id) then |
|
return false |
|
end |
|
local value = self:GetProperty(prop_id) |
|
for _, lm_id in ipairs(self:GetLightmodelRefs()) do |
|
local lm = LightmodelPresets[lm_id] |
|
lm:SetProperty(prop_id, value) |
|
ObjModified(lm) |
|
if LightmodelOverride and LightmodelOverride == lm then |
|
lm:OnEditorSetProperty(prop_id, old_value, ged) |
|
end |
|
end |
|
end |
|
|
|
DefineClass.LightmodelPart = { |
|
__parents = {"PropertyObject"}, |
|
properties = { |
|
}, |
|
PresetClass = "LightmodelPart", |
|
} |
|
|
|
|
|
|
|
|
|
RainTypeItems = { |
|
{ value = "RainLight", text = "Light" }, |
|
{ value = "RainMedium", text = "Medium" }, |
|
{ value = "RainHeavy", text = "Heavy" }, |
|
} |
|
|
|
DefineClass.LightmodelRain = { |
|
__parents = {"LightmodelPart"}, |
|
lightmodel_feature = "rain", |
|
lightmodel_category = "Rain", |
|
group = "LightmodelRain", |
|
properties = { |
|
{ name = "Rain", id = "rain_enable", editor = "bool", default = false, help = "Switches on and off rain." }, |
|
{ name = "Rain Type", id = "rain_type", editor = "combo", default = "RainMedium", items = RainTypeItems, no_edit = PropChecker("rain_enable", false) }, |
|
{ name = "Rain Color", id = "rain_color", editor = "color", default = RGBA(255, 255, 255, 255), help = "Models the light properties of the comprising liquid." }, |
|
{ name = "Drops Count", id = "rain_drops_count", editor = "number", slider = true, min = 1, max = const.RainMaxDropsCount, default = 1, help = "Mean rain drops count per cubic meter." }, |
|
{ name = "Drop Radius", id = "rain_drop_radius", editor = "number", slider = true, min = const.RainMinDropRadius, max = const.RainMaxDropRadius, default = const.RainMinDropRadius, help = "Mean radius used to model properties such as terminal velocity, volume, sprey in microns." }, |
|
{ name = "Ground Wetness", id = "rain_ground_wetness", editor = "number", slider = true, min = 0, max = 100, default = 50, scale = 100, help = "How much material properties will be changed by rain shaders." }, |
|
|
|
{ name = "Lightning", id = "lightning_enable", editor = "bool", default = false, blend = const.LightningBlendThreshold }, |
|
{ name = "Lightning Delay Start", id = "lightning_delay_start", editor = "number", default = 15000, scale = "sec", slider = true }, |
|
{ name = "Lightning Interval Min", id = "lightning_interval_min", editor = "number", default = 3000, scale = "sec", slider = true }, |
|
{ name = "Lightning Interval Max", id = "lightning_interval_max", editor = "number", default = 120000, scale = "sec", slider = true }, |
|
{ name = "Lightning Chance", id = "lightning_strike_chance", editor = "number", default = 40, scale = "%", min = 0, max = 100, slider = true, help = "out of 100, rest are distant thunder." }, |
|
{ name = "Lightning Chance Vertical", id = "lightning_vertical_chance", editor = "number", default = 60, scale = "%", min = 0, max = 100, slider = true, help = "If the lightning strike is vertical, otherwise it's horizontal." }, |
|
}, |
|
} |
|
|
|
function OnMsg.LightmodelSetSceneParams(view, lm_buf, time, start_offset) |
|
SetSceneParam(view, "RainEnable", lm_buf.rain_enable and 1 or 0, 0, start_offset) |
|
SetSceneParamColor(view, "RainColor", lm_buf.rain_color, time, start_offset) |
|
SetSceneParam(view, "RainDropsCount", lm_buf.rain_drops_count, time, start_offset) |
|
SetSceneParam(view, "RainDropRadius", lm_buf.rain_drop_radius, time, start_offset) |
|
SetSceneParam(view, "RainGroundWetness", lm_buf.rain_ground_wetness, time, start_offset) |
|
end |
|
|
|
local default_raw_path = insideHG() and ConvertToBenderProjectPath("/DaVinci Resolve/RAW Screenshots/") or ConvertToOSPath("AppData/RAW Screenshots") |
|
|
|
DefineClass.LightmodelColorGrading = { |
|
__parents = {"LightmodelPart"}, |
|
lightmodel_feature = "color_grading", |
|
lightmodel_category = "Color Grading", |
|
group = "LightmodelColorGrading", |
|
properties = { |
|
{ name = "Gamma", id = "gamma", editor = "color", default = RGB(128, 128, 128), buttons = {{name = "Gray", func = "Gray"}}, help = "Performs nonlinear gamma correction." }, |
|
{ name = "Desaturation", id = "desaturation", editor = "number", default = 0, min = -100, max = 100, scale = 100, slider = true, help = "Performs LDR color desaturation as part of tone mapping." }, |
|
{ name = "Base Color Desat", id = "base_color_desat", editor = "number", default = 0, min = -1000, max = 1000, scale = 1000, slider = true, help = "Performs color desaturation on the diffuse texture" }, |
|
{ name = "LUT", id = "grading_lut", editor = "preset_id", default = "Default", preset_class = "GradingLUTSource", help = string.format("Grading LUT in %s %s.", GetColorSpaceName(hr.ColorGradingLUTColorSpace), GetColorGammaName(hr.ColorGradingLUTColorGamma)) }, |
|
{ name = "RAW Screenshot Path", id = "raw_screenshot_path", dont_save = true, editor = "browse", default = default_raw_path, filter = "OpenEXR (*.exr)|*.exr", os_path = true, allow_missing = true, folder = { { default_raw_path, os_path = true } }, buttons = {{name = "Screenshot", func = "CaptureRAWScreenshot"}}}, |
|
{ name = "Post Grading LUT Path", id = "post_grading_lut_path", editor = "browse", default = "", filter = "LUT (*.cube)|*.cube", folder = { "svnAssets/Source/Editor/DeVinci Resolve/Viewing LUTs/" }, allow_missing = true}, |
|
{ name = "Post Grading LUT Size", id = "post_grading_lut_size", editor = "choice", default = 65, items = { 16, 17, 32, 33, 64, 65 }, buttons = {{name = "Capture", func = "CapturePostGradingLUT"}} }, |
|
}, |
|
} |
|
|
|
function LightmodelColorGrading:CaptureRAWScreenshot(root, prop_id, ged) |
|
hr.PostProcRAWOutputPath = self.raw_screenshot_path |
|
end |
|
|
|
function LightmodelColorGrading:CapturePostGradingLUT(root, prop_id, ged) |
|
if self.post_grading_lut_path == "" then |
|
return |
|
end |
|
ExportToneMappingLUT(self.post_grading_lut_size, self.post_grading_lut_path) |
|
end |
|
|
|
function LightmodelColorGrading:Setpost_grading_lut_path(value) |
|
self.post_grading_lut_path = AppendDefaultExtension(value, ".cube") |
|
end |
|
|
|
function LightmodelColorGrading:Setraw_screenshot_path(value) |
|
self.raw_screenshot_path = AppendDefaultExtension(value, ".exr") |
|
end |
|
|
|
function OnMsg.LightmodelSetSceneParams(view, lm_buf, time, start_offset) |
|
SetSceneParamColor(view, "Gamma", lm_buf.gamma, time, start_offset, not "gamma-encoded") |
|
SetSceneParam(view, "Desaturation", lm_buf.desaturation, time, start_offset) |
|
SetSceneParam(view, "BaseColorDesat", lm_buf.base_color_desat, time, start_offset) |
|
|
|
local grading_lut_preset_id = lm_buf.grading_lut |
|
if grading_lut_preset_id == "" or not GradingLUTs[lm_buf.grading_lut] then |
|
grading_lut_preset_id = "Default" |
|
end |
|
|
|
local grading_lut_resource_id = ResourceManager.GetResourceID(GradingLUTs[grading_lut_preset_id]:GetResourcePath()) |
|
SetGradingLUT(view, grading_lut_resource_id, time, start_offset) |
|
end |
|
|
|
DefineClass.LightmodelOpticalAnomalies = { |
|
__parents = {"LightmodelPart"}, |
|
lightmodel_feature = "optical_anomalies", |
|
lightmodel_category = "Optical Anomalies", |
|
group = "LightmodelOpticalAnomalies", |
|
properties = { |
|
{ category = "Vignette", name = "Tint Color", id = "vignette_tint_color", editor = "color", default = RGBA(0,0,0,0), help = "Vignette tint color." }, |
|
{ category = "Vignette", name = "Tint Start", id = "vignette_tint_start", editor = "number", float = true, slider = true, step = 0.001, min = 0.0, max = 1.0, default = 0.7, help = "Start radius of the gradient towards pure color." }, |
|
{ category = "Vignette", name = "Tint Feather", id = "vignette_tint_feather", editor = "number", slider = true, float = true, step = 0.001, min = 0.0, max = 1.0, default = 1.0, help = "How large the gradient towards pure color is." }, |
|
{ category = "Vignette", name = "Darken Opacity", id = "vignette_darken_opacity", editor = "number", float = true, slider = true, step = 0.001, min = 0, max = 1.0, default = 0.0, help = "The opacity of the vignette layer." }, |
|
{ category = "Vignette", name = "Darken Start", id = "vignette_darken_start", editor = "number", float = true, slider = true, step = 0.001, min = 0.0, max = 1.0, default = 0.7, help = "Start radius of the gradient towards black." }, |
|
{ category = "Vignette", name = "Darken Feather", id = "vignette_darken_feather", editor = "number", float = true, slider = true, step = 0.001, min = 0.0, max = 1.0, default = 1.0, help = "How large the gradient towards black is." }, |
|
{ category = "Vignette", name = "Circularity", id = "vignette_circularity", editor = "number", float = true, slider = true, step = 0.01, min = 0.0, max = 1.0, default = 0.0, help = "Control gradient roundness." }, |
|
|
|
{ category = "Chromatic Aberration", name = "Intensity", id = "chromatic_aberration_intensity", editor = "number", float = true, slider = true, step = 0.001, min = 0.0, max = 10.0, default = 0.0 }, |
|
{ category = "Chromatic Aberration", name = "Start", id = "chromatic_aberration_start", editor = "number", float = true, slider = true, step = 0.001, min = 0.0, max = 1.0, default = 0.0 }, |
|
{ category = "Chromatic Aberration", name = "Feather", id = "chromatic_aberration_feather", editor = "number", float = true, slider = true, step = 0.001, min = 0.0, max = 1.0, default = 1.0 }, |
|
{ category = "Chromatic Aberration", name = "Circularity", id = "chromatic_aberration_circularity", editor = "number", float = true, slider = true, step = 0.01, min = 0.0, max = 1.0, default = 0.0 }, |
|
}, |
|
} |
|
|
|
function OnMsg.LightmodelSetSceneParams(view, lm_buf, time, start_offset) |
|
local vignette_tint_max = lm_buf:GetPropertyMetadata("vignette_tint_start").max |
|
local vignette_tint_end = |
|
lm_buf.vignette_tint_start + (vignette_tint_max - lm_buf.vignette_tint_start) * lm_buf.vignette_tint_feather |
|
|
|
SetSceneParamColor(view, "VignetteTintColor", lm_buf.vignette_tint_color, time, start_offset) |
|
SetSceneParamFloat(view, "VignetteTintStart", lm_buf.vignette_tint_start, time, start_offset) |
|
SetSceneParamFloat(view, "VignetteTintEnd", vignette_tint_end, time, start_offset) |
|
SetSceneParamFloat(view, "VignetteCircularity", lm_buf.vignette_circularity, time, start_offset) |
|
|
|
local vignette_darken_max = lm_buf:GetPropertyMetadata("vignette_darken_start").max |
|
local vignette_darken_end = |
|
lm_buf.vignette_darken_start + (vignette_darken_max - lm_buf.vignette_darken_start) * lm_buf.vignette_darken_feather |
|
|
|
SetSceneParamFloat(view, "VignetteDarkenOpacity", lm_buf.vignette_darken_opacity, time, start_offset) |
|
SetSceneParamFloat(view, "VignetteDarkenStart", lm_buf.vignette_darken_start, time, start_offset) |
|
SetSceneParamFloat(view, "VignetteDarkenEnd", vignette_darken_end, time, start_offset) |
|
|
|
local chromatic_aberration_max = lm_buf:GetPropertyMetadata("chromatic_aberration_start").max |
|
local chromatic_aberration_end = |
|
lm_buf.chromatic_aberration_start + (chromatic_aberration_max - lm_buf.chromatic_aberration_start) * lm_buf.chromatic_aberration_feather |
|
|
|
SetSceneParamFloat(view, "ChromaticAberrationIntensity", lm_buf.chromatic_aberration_intensity, time, start_offset) |
|
SetSceneParamFloat(view, "ChromaticAberrationStart", lm_buf.chromatic_aberration_start, time, start_offset) |
|
SetSceneParamFloat(view, "ChromaticAberrationEnd", chromatic_aberration_end, time, start_offset) |
|
SetSceneParamFloat(view, "ChromaticAberrationCircularity", lm_buf.chromatic_aberration_circularity, time, start_offset) |
|
end |
|
|
|
DefineClass.LightmodelTranslucency = { |
|
__parents = {"LightmodelPart"}, |
|
lightmodel_feature = "translucency", |
|
lightmodel_category = "Translucency", |
|
group = "LightmodelTranslucency", |
|
properties = { |
|
{ name = "Scale", id = "translucency_scale", editor = "number", float = true, slider = true, step = 0.001, default = 0.3, min = 0.0, max = 1.0, help = "Translucency overall scale" }, |
|
{ name = "Distort Sun Direction", id = "translucency_distort_sun_dir", editor = "number", float = true, slider = true, default = 0.12, min = 0.0, max = 2.0, help = "How much to distort the sun direction toward the material normal" }, |
|
{ name = "Sun Falloff", id = "translucency_sun_falloff", editor = "number", float = true, slider = true, step = 0.001, default = 30.0, min = 0.0, max = 50.0, help = "Power that controls how fast the sun contribution falls off when with the difference of direction between the view and the sun" }, |
|
{ name = "Sun Scale", id = "translucency_sun_scale", editor = "number", float = true, slider = true, step = 0.001, default = 0.2, min = 0.0, max = 1.0, help = "Sunlight contribution scale" }, |
|
{ name = "Ambient Scale", id = "translucency_ambient_scale", editor = "number", float = true, slider = true, step = 0.001, default = 0.02, min = 0.0, max = 1.0, help = "Ambient contribution scale" }, |
|
{ name = "Base Luminance", id = "translucency_base_luminance", editor = "number", float = true, slider = true, step = 0.001, default = 1.335, min = 0.0, max = 3.0, help = "Assumed base light luminance" }, |
|
{ name = "Base Color Temperature", id = "translucency_base_k", editor = "number", float = true, slider = true, step = 1.0, default = 3600.0, min = 1000.0, max = 6500.0, help = "Assumed sunlight base temperature in degrees K" }, |
|
{ name = "Reduce Color Temperature", id = "translucency_reduce_k", editor = "number", float = true, slider = true, step = 1.0, default = 1000.0, min = 0.0, max = 5000.0, help = "Color reduction temperature in degrees K" }, |
|
{ name = "Desaturation", id = "translucency_desaturation", editor = "number", float = true, slider = true, step = 0.001, default = 0.3, min = 0.0, max = 1.0, help = "Amount to desaturate the color of translucent light" }, |
|
}, |
|
} |
|
|
|
function OnMsg.LightmodelSetSceneParams(view, lm_buf, time, start_offset) |
|
SetSceneParamFloat(view, "TranslucencyScale", lm_buf.translucency_scale, time, start_offset) |
|
SetSceneParamFloat(view, "TranslucencySunDirDistort", lm_buf.translucency_distort_sun_dir, time, start_offset) |
|
SetSceneParamFloat(view, "TranslucencySunFalloff", lm_buf.translucency_sun_falloff, time, start_offset) |
|
SetSceneParamFloat(view, "TranslucencySunScale", lm_buf.translucency_sun_scale, time, start_offset) |
|
SetSceneParamFloat(view, "TranslucencyAmbientScale", lm_buf.translucency_ambient_scale, time, start_offset) |
|
SetSceneParamFloat(view, "TranslucencyBaseLuminance", lm_buf.translucency_base_luminance, time, start_offset) |
|
SetSceneParamFloat(view, "TranslucencyBaseK", lm_buf.translucency_base_k, time, start_offset) |
|
SetSceneParamFloat(view, "TranslucencyReduceK", lm_buf.translucency_reduce_k, time, start_offset) |
|
SetSceneParamFloat(view, "TranslucencyDesaturate", lm_buf.translucency_desaturation, time, start_offset) |
|
end |
|
|
|
DefineClass.LightmodelClouds = { |
|
__parents = {"LightmodelPart"}, |
|
lightmodel_feature = "clouds", |
|
lightmodel_category = "Clouds", |
|
group = "LightmodelClouds", |
|
properties = { |
|
{ category = "Cloud shadows", feature = "clouds", name = "Clouds shadow strength", id = "clouds_strength", default = 0, editor = "number", slider = true, min = 0, max = 1000, scale = 1000, help = "Maximum clouds darkness. Clouds source texture path is CommonAssets/System/clouds.dds." }, |
|
{ category = "Cloud shadows", feature = "clouds", name = "Clouds shadow coverage", id = "clouds_coverage", default = 500, editor = "number", slider = true, min = 0, max = 1000, scale = 1000, help = "How much of the surface is covered with clouds." }, |
|
{ category = "Cloud shadows", feature = "clouds", name = "Clouds shadow smoothness", id = "clouds_smoothness", default = 300, editor = "number", slider = true, min = 0, max = 1000, scale = 1000, help = "How sharp are the edges of the clouds." }, |
|
{ category = "Cloud shadows", feature = "clouds", name = "Clouds shadow scrub", id = "clouds_phase", default = 0, editor = "number", slider = true, min = 0, max = 1000, scale = 1000, help = "Scrub back and forth to see clouds move.", dont_save = true }, |
|
{ category = "Cloud shadows", feature = "clouds", name = "Clouds shadow scale", id = "clouds_scale", default = 1000, editor = "number", slider = true, min = 300, max = 10000, scale = 1000, help = "When interpolating lightmodels the clouds scale should be the same, otherwise the clouds will appear to move rapidly." }, |
|
{ category = "Cloud shadows", feature = "clouds", name = "Oscillation period", id = "clouds_osci_period", default = 5000, editor = "number", slider = true, min = 2000, max = 3600 * 1000, scale = 1000, }, |
|
{ category = "Cloud shadows", feature = "clouds", name = "Oscillation amplitude", id = "clouds_osci_amplitude", default = 0, editor = "number", slider = true, min = 0, max = 2000, scale = 1000, }, |
|
{ category = "Cloud shadows", feature = "clouds", name = "Clouds direction", id = "clouds_dir", default = 0, editor = "number", scale = "deg", slider = true, min = 0, max = 360*60, help = "The direction of cloud movement in degrees." }, |
|
{ category = "Cloud shadows", feature = "clouds", name = "Wind strength", id = "clouds_wind_strength", default = 0, editor = "number", scale = 1000, slider = true, min = 0, max = 1000, help = "Should clouds be affected by wind?" }, |
|
{ category = "Cloud shadows", feature = "clouds", name = "Clouds speed (m/s)", id = "clouds_speed", default = 3000, editor = "number", scale = 1000, slider = true, min = 0, max = 50*guim, help = "Clouds movement in meters per second." }, |
|
} |
|
} |
|
|
|
function OnMsg.LightmodelSetSceneParams(view, lm_buf, time, start_offset) |
|
if not config.LightModelUnusedFeatures["clouds"] then |
|
SetSceneParam(view, "CloudsStrength", lm_buf.clouds_strength, time, start_offset) |
|
SetSceneParam(view, "CloudsCoverage", lm_buf.clouds_coverage, time, start_offset) |
|
SetSceneParam(view, "CloudsSmoothness", lm_buf.clouds_smoothness, time, start_offset) |
|
SetSceneParam(view, "CloudsSpeed", lm_buf.clouds_speed, time, start_offset) |
|
SetSceneParam(view, "CloudsPhase", lm_buf.clouds_phase, time, start_offset) |
|
SetSceneParam(view, "CloudsDirectionSP", lm_buf.clouds_dir, time, start_offset) |
|
SetSceneParam(view, "CloudsWindStrength", lm_buf.clouds_wind_strength, time, start_offset) |
|
SetSceneParam(view, "CloudsScale", lm_buf.clouds_scale, time, start_offset) |
|
SetSceneParam(view, "CloudsOsciPeriod", lm_buf.clouds_osci_period, time, start_offset) |
|
SetSceneParam(view, "CloudsOsciAmplitude", lm_buf.clouds_osci_amplitude, time, start_offset) |
|
end |
|
end |
|
|
|
|
|
AutoExposureInstructions = |
|
[[To adjust exposure: |
|
- turn off via button to the right |
|
- view a representative mid-brightness scene |
|
- reset Exposure to default value |
|
- adjust brightness using sun intensity, envmaps exposure, and if all else fails, Exposure |
|
- switch to split mode using button to the right |
|
- adjust Auto Exposure until the two parts of the screen match in brightness |
|
- verify by moving the camera to a dark and to a bright spot]] |
|
|
|
CubemapInstructions = [[Usually the sky is fetched from the cubemap, but when capturing the cubemap the sky is unavailable and approximated by a slower method. |
|
- Please use the "Cubemap capture preview" toggle to see the result of the slower method in real time. |
|
- Make sure to use this for "Bake" lightmodels. |
|
]] |
|
|
|
local sky_custom_sun_ro = function(self) return not self.sky_custom_sun or self.use_time_of_day end |
|
local shadow_range_ro = function(self) return not self.shadow end |
|
local custom_sun_ro = function(self) return self.use_time_of_day end |
|
local tod_ro = function(self) return not self.use_time_of_day end |
|
DefineClass.Lightmodel = { |
|
__parents = { "PropertyObject" }, |
|
properties = { |
|
{ category = "Sun", feature = "phys_sky", name = "Sun diffuse color", id = "sun_diffuse_color", editor = "color", default = RGB(255, 255, 255), help = "The color of sunlight.\nAffects the diffuse contribution of the Sun." }, |
|
{ category = "Sun", feature = "phys_sky", name = "Sun diffuse intensity", id = "sun_intensity", editor = "number", slider=true, min = 0, max = 2500, default = 100, help = "The intensity of the sun diffuse contribution." }, |
|
{ category = "Sun", feature = "phys_sky", name = "Sun specular intensity", id = "sun_angular_radius", editor = "number", slider=true, min = 0, max = 2500, default = 100, help = "The intensity of the sun specular contribution." }, |
|
{ category = "Sun", feature = "shadow", name = "Shadow", id = "shadow", editor = "number", slider = true, min = 0, max = 1000, scale = 1000, default = 1000, help = "Shadow strength." }, |
|
{ category = "Sun", feature = "shadow", name = "Shadow range", id = "shadow_range", editor = "number", slider = true, min = 0, max = 10000 * guim, scale = "m", default = 500 * guim, help = "Limits the distance at which the shadows are visible.", read_only = shadow_range_ro }, |
|
|
|
{ category = "Sun (dev tools)", feature = "sun_path", id = "_help", editor = "help", help = "These are not saved; use to tweak sun parameters for testing." }, |
|
{ category = "Sun (dev tools)", feature = "sun_path", name = "Sunrise time", id = "sunrise_time", editor = "number", default = 8*60, help = "", dont_save = true }, |
|
{ category = "Sun (dev tools)", feature = "sun_path", name = "Sunset time", id = "sunset_time", editor = "number", default = 20*60, help = "", dont_save = true }, |
|
{ category = "Sun (dev tools)", feature = "sun_path", name = "Earth time info", id = "sun_earthtime_info", editor = "text", default = "", help = "", dont_save = true, read_only = true}, |
|
{ category = "Sun (dev tools)", feature = "sun_path", name = "Sunrise azi", id = "sunrise_azi", editor = "number", default = 54*60, slider = true, min = 0*60, max = 360*60, scale = "deg", help = "Azimuth is from 0Deg North, 90Deg East ... 360Deg. Sunrise azi + Sunset azi generally should make 360Deg.", dont_save = true }, |
|
{ category = "Sun (dev tools)", feature = "sun_path", name = "Sunset azi", id = "sunset_azi", editor = "number", default = 306*60, help = "Azimuth is from 0Deg North, 90Deg East ... 360Deg. Sunrise azi + Sunset azi generally should make 360Deg.", slider = true, min = 0*60, max = 360*60, scale = "deg", dont_save = true }, |
|
{ category = "Sun (dev tools)", feature = "sun_path", name = "Sun max elevation", id = "sun_max_elevation", editor = "number", default = 70*60, help = "This is the maximum angle from the horizon to the center of the sun disk (reached at noon).", slider = true, min = 0, max = 89*60, scale = "deg", dont_save = true }, |
|
{ category = "Sun (dev tools)", feature = "sun_path", name = "Sun shadow min", id = "sun_shadow_min", editor = "number", default = 15*60, help = "This is the min elevation that the sun will cast shadows from to avoid super long shadows.", slider = true, min = 0, max = 89*60, scale = "deg", dont_save = true }, |
|
{ category = "Sun (dev tools)", feature = "sun_path", name = "North rotation", id = "sun_nr", editor = "number", default = 0, help = "Add this angle to all azimuths to effectively rotate where North is on the map.", slider = true, min = 0*60, max = 360*60, scale = "deg", dont_save = true }, |
|
|
|
{ category = "Sun Pos", feature = "phys_sky", name = "Use time of day", id = "use_time_of_day", editor = "bool", default = true, help = "Sun position is determined by the current time of day setup." }, |
|
{ category = "Sun Pos", feature = "phys_sky", name = "Start Time (h)", id = "time", editor = "number", default = 12*60, scale = 60, min = 0, max = 24*60, slider = true, help = "This is the time when the blending to this model will start. View shows it ignoring blending.", read_only = tod_ro, buttons = {{name = "View", func = "PreviewStart"}}}, |
|
{ category = "Sun Pos", feature = "phys_sky", name = "End Time", id = "time_next", editor = "text", default = "", help = "This is the time when the blending to next model will start. View shows it ignoring blending.", read_only = true, dont_save = true, buttons = {{name = "View", func = "PreviewEnd"}}}, |
|
{ category = "Sun Pos", feature = "phys_sky", name = "Blend Duration (m)", id = "blend_time", editor = "number", default = 60, help = "Controls the duration of the blend. View buttons take into account the blending, i.e. 'Start' shows accurately the end of the previous model.", read_only = tod_ro, buttons = {{name = "Start", func = "PreviewBlendStart"}, {name = "End", func = "PreviewBlendEnd"}, {name = "Preview", func = "PreviewBlend"}}}, |
|
{ category = "Sun Pos", feature = "phys_sky", name = "Sun alt", id = "sun_alt", min = -1800, max = 1800, editor = "number", slider = true, scale = 10, default = 250, help = "At what angle (in 1/10 degrees) relative to the horizon (height) is the Sun.", read_only = custom_sun_ro }, |
|
{ category = "Sun Pos", feature = "phys_sky", name = "Sun shadow alt", id = "sun_shadow_height", editor = "number", default = 0, slider = true, scale = 10, min = 0, max = 1800, help = "0 = Use sun alt for shadow direction. > 0 forces shadows as if the sun is at this altitutude", read_only = custom_sun_ro}, |
|
{ category = "Sun Pos", feature = "phys_sky", name = "Sun azi", id = "sun_azi", min = 0, max = 360, editor = "number" , slider = true, default = 180, help = "The position of the Sun relative to the world, specified as an angle in degrees.", read_only = custom_sun_ro }, |
|
{ category = "Sun Pos", feature = "phys_sky", name = "Sky custom sun", id = "sky_custom_sun", editor = "bool" , default = false, help = "If checked allows overriding the disk sun position with a separate custom one for the sun in the sky.", read_only = custom_sun_ro }, |
|
{ category = "Sun Pos", feature = "phys_sky", name = "Sky custom sun azi", id = "sky_custom_sun_azi", min = 0, max = 360, editor = "number" , slider = true, default = 180, help = "The azimuth of Sun in the Sky, specified as an angle in degrees." , read_only = sky_custom_sun_ro }, |
|
{ category = "Sun Pos", feature = "phys_sky", name = "Sky custom sun alt", id = "sky_custom_sun_alt", min = -1800, max = 1800, editor = "number", slider = true, default = 0, help = "The altitude of Sun in the Sky, specified as an angle in degrees.", read_only = sky_custom_sun_ro}, |
|
|
|
{ category = "Sky", feature = "phys_sky", id = "__", editor = "help", name = "Cubemap help", help = CubemapInstructions, }, |
|
{ category = "Sky", feature = "phys_sky", name = "Mie coefs", id = "mie_coefs", editor = "color", default = RGB(210, 210, 210), help = "Mie coefficients control sun color. It is also affected by the Rayleight param." }, |
|
{ category = "Sky", feature = "phys_sky", name = "Rayleigh coefs", id = "ray_coefs", editor = "color", default = RGB(55, 130, 221), help = "Rayleigh coefficient control sky color. It is also affected by the Mie param." }, |
|
{ category = "Sky", feature = "phys_sky", name = "Mie scale height", id = "mie_sh", editor = "number", slider = true, min=100, max = 10000, default = 1200, help = "Mie scale height controls the height at which the atmosphere is half dense for this scattering." }, |
|
{ category = "Sky", feature = "phys_sky", name = "Rayleigh scale height", id = "ray_sh", editor = "number", slider = true, min=1000, max = 16000, default = 7994, help = "Rayleigh scale height controls the height at which the atmosphere is half dense for this scattering." }, |
|
{ category = "Sky", feature = "phys_sky", name = "Mie Shape", id = "mie_mc", editor = "number", slider = true, min=750, max = 999, default = 860, help = "The G param (mean cosine) controls the asymmetry (shape) of the mie phase function." }, |
|
{ category = "Sky", feature = "phys_sky", name = "Exposure", id = "sky_exp", min = -1000, max = 1000, default = 0, editor = "number" , slider = true, help = "The exposure control in 1/100 EV. Intensity change is pow(2, E / 100)" }, |
|
{ category = "Sky", feature = "phys_sky", name = "Sky IS", id = "sky_is", editor=false, dont_save = true, default = false, help = "Toggles realtime update of sky contribution with importance sampling (for lightmodel tweak only)" }, |
|
{ category = "Sky", feature = "phys_sky", name = "Cubemap capture preview", editor = "bool", dont_save = true, id = "cubemap_capture_preview", default = false, help = "Mostly enables Sky importance sampling, among other things" }, |
|
|
|
{ category = "Cubemap", feature = "phys_sky", name = "Exterior Env map", id = "exterior_envmap", default = "PainterStudioDaylight", editor = "dropdownlist", help = "The current exterior environment map texture.", items = function() return GetEnvMapsList("Exterior") end }, |
|
{ category = "Cubemap", feature = "phys_sky", name = "Exterior Env Exposure", id = "ext_env_exposure", min = -1000, max = 1000, default = 0, editor = "number" , slider = true, help = "The exterior env exposure control in 1/100 EV. Intensity change is pow(2, E / 100)" }, |
|
{ category = "Cubemap", feature = "phys_sky", name = "Exterior Env Map Image", id = "ExteriorEnvmapImage", editor = "image", default = "", dont_save = true, img_size = 128, img_box = 1 }, |
|
{ category = "Cubemap", feature = "phys_sky", name = "Interior Env map", id = "interior_envmap", default = "PainterStudioDaylight", editor = "dropdownlist", help = "The current interior environment map texture.", items = function() return GetEnvMapsList("Interior") end }, |
|
{ category = "Cubemap", feature = "phys_sky", name = "Interior Env Exposure", id = "int_env_exposure", min = -1000, max = 1000, default = 0, editor = "number" , slider = true, help = "The interior env exposure control in 1/100 EV. Intensity change is pow(2, E / 100)" }, |
|
{ category = "Cubemap", feature = "phys_sky", name = "Interior Env Map Image", id = "InteriorEnvmapImage", editor = "image", default = "", dont_save = true, img_size = 128, img_box = 1 }, |
|
|
|
{ category = "Night Sky", feature = "phys_sky", name = "Stars Intensity", id = "stars_intensity", min = 0, max = 1000, scale = 1000, editor = "number", slider = true, default = 0, help = "Controls the brightness of the stars." }, |
|
{ category = "Night Sky", feature = "phys_sky", name = "Stars Blue tint", id = "stars_blue_tint", min = 0, max = 100, scale = 100, editor = "number", slider = true, default = 30, help = "Faint stars are tinted blue to simulate human perception in low-light conditions." }, |
|
{ category = "Night Sky", feature = "phys_sky", name = "MilkyWay Intensity", id = "mw_intensity", min = 0, max = 1000, scale = 1000, editor = "number", slider = true, default = 0, help = "Controls the brightness of the milky way texture." }, |
|
{ category = "Night Sky", feature = "phys_sky", name = "MilkyWay Blue tint", id = "mw_blue_tint", min = 0, max = 100, scale = 100, editor = "number", slider = true, default = 30, help = "MilkyWay is tinted blue to simulate human perception in low-light conditions." }, |
|
{ category = "Night Sky", feature = "phys_sky", name = "Rotation", id = "stars_rotation", min = 0, max = 3600, editor = "number", slider = true, default = 0, scale = 10, help = "Rotation angle of the stars around the celestial pole" }, |
|
{ category = "Night Sky", feature = "phys_sky", name = "Celestial Pole Altitude", id = "stars_pole_alt", min = 0, max = 1800, editor = "number", slider = true, default = 0, scale = 10, help = "Celestial pole altitude in degrees. Approximately equal to the observer's latitude position on Earth." }, |
|
{ category = "Night Sky", feature = "phys_sky", name = "Celestial Pole Azimuth", id = "stars_pole_azi", min = 0, max = 3600, editor = "number", slider = true, default = 0, scale = 10, help = "Celestial pole azimuth in degrees. Should point to North on Earth. Related to the Sun azimuth." }, |
|
|
|
{ category = "Env Capture", feature = "phys_sky", name = "Sky Exp Exterior Adjust", id = "env_exterior_capture_sky_exp", editor="number", default = "", min = -1000, max = 1000, default = 0, editor = "number" , slider = true, help = "Adjusts the sky exposure in the captured exterior cubemap"}, |
|
{ category = "Env Capture", feature = "phys_sky", name = "Sun Int Exterior Adjust", id = "env_exterior_capture_sun_int", editor="number", default = "", min = -2500, max = 2500, default = 0, editor = "number" , slider = true, help = "Adjusts the sun intensity in the captured exterior cubemap"}, |
|
{ category = "Env Capture", feature = "phys_sky", name = "Exterior Capture Pos", id = "env_exterior_capture_pos", editor="point", default = InvalidPos(), helper = "absolute_pos", help = "The position to capture the exterior env map from.", buttons = {{name = "View", func = "ViewExteriorEnvPos" }, {name ="Use Shaderball", func = "UseSelectionAsExteriorEnvPos"}}, scale = "m"}, |
|
{ category = "Env Capture", feature = "phys_sky", name = "Sky Exp Interior Adjust", id = "env_interior_capture_sky_exp", editor="number", default = "", min = -1000, max = 1000, default = 0, editor = "number" , slider = true, help = "Adjusts the sky exposure in the captured interior cubemap"}, |
|
{ category = "Env Capture", feature = "phys_sky", name = "Sun Int Interior Adjust", id = "env_interior_capture_sun_int", editor="number", default = "", min = -2500, max = 2500, default = 0, editor = "number" , slider = true, help = "Adjusts the sun intensity in the captured interior cubemap"}, |
|
{ category = "Env Capture", feature = "phys_sky", name = "Interior Capture Pos", id = "env_interior_capture_pos", editor="point", default = InvalidPos(), helper = "absolute_pos", help = "The position to capture the interior env map from.", buttons = {{name = "View", func = "ViewInteriorEnvPos" }, {name ="Use Shaderball", func = "UseSelectionAsInteriorEnvPos"}}, scale = "m"}, |
|
{ category = "Env Capture", feature = "phys_sky", name = "Map for Cubemaps", id = "env_capture_map", editor="text", default = "", read_only=true, help = "The map name on which the position of the last capture is"}, |
|
{ category = "Env Capture", feature = "phys_sky", name = "Capture", id = "env_capture", editor="text", default = "", read_only=true, help = "Click to capture cubemaps", buttons = {{name = "Exterior", func = "CaptureExteriorEnvmap"}, {name = "Interior", func = "CaptureInteriorEnvmap"}, {name = "Both", func = "CaptureBothEnvmaps"}}}, |
|
{ category = "Env Capture", feature = "phys_sky", name = "View Map", id = "env_view_site", editor = "dropdownlist", items = {"Exterior", "Interior"}, default = "Exterior", dont_save = true, buttons = {{name = "View", func = "ViewEnv"}, {name = "Hide", func = "HideEnv"}}}, |
|
{ category = "Env Capture", feature = "phys_sky", name = "Convert HDR Pano", id = "hdr_pano", editor = "browse", default = false, filter = "Radiance HDR File|*.hdr", default = "", dont_save = true, buttons = {{name = "Exterior", func = "ConvertExteriorEnvmap"}, {name = "Interior", func = "ConvertInteriorEnvmap"}}}, |
|
{ category = "Env Capture", feature = "phys_sky", name = "Lightmodel for Capture", id = "lm_capture", editor = "preset_id", preset_class = "LightmodelPreset", default = "", help = "Indicates which light model should be used for the baking.", no_validate = true, }, |
|
|
|
{ category = "Fog", feature = "fog", name = "Fog color", id = "fog_color", default = RGB(180, 180, 180), editor = "color", help = "The default color of the fog." }, |
|
{ category = "Fog", feature = "fog", name = "Fog density", id = "fog_density", default = 20, min = 0, max = 2000, scale = 100, editor = "number", slider = true, help = "The fog thickness." }, |
|
{ category = "Fog", feature = "fog", name = "Fog height falloff", id = "fog_height_falloff" , default = 1500, min = 1, max = 2500, editor = "number", slider = true, help = "The fog thickness change with height" }, |
|
{ category = "Fog", feature = "fog", name = "Fog start (m)", id = "fog_start", default = 0, min = 0, max = 1000 * 1000, scale = 1000, editor = "number" , slider = true, help = "The distance to fog start, in meters."}, |
|
|
|
{ category = "Water", feature = "water", name = "Water Color", id = "water_color", editor = "color", default = RGB(127, 127, 127), help = "The color of the terrain water" }, |
|
{ category = "Water", feature = "water", name = "Opacity Modifier", id = "absorption_coef", min = 0, max = 100, default = 100, scale = 100, editor = "number", slider = true, help = "How much light does the water absorb" }, |
|
{ category = "Water", feature = "water", name = "Reflection Modifier", id = "minimum_depth", min = 0, max = 200, default = 100, scale = 100, editor = "number", slider = true, help = "How deep will the water appear minimally" }, |
|
|
|
{ category = "Ice", feature = "ice", name = "Ice color", id = "ice_color", editor = "color", default = RGB(255, 255, 255), help = "The color of the ice that will affect the buildings and rocks" }, |
|
{ category = "Ice", feature = "ice", name = "Ice strength", id = "ice_strength", min = 0, max = 100, default = 0, scale = 100, editor = "number", slider = true, help = "How strong will be ice get" }, |
|
|
|
{ category = "Snow", feature = "snow", name = "Snow color", id = "snow_color", editor = "color", default = RGB(167, 167, 167), help = "The color of the snow of the terrain" }, |
|
{ category = "Snow", feature = "snow", name = "Snow direction X", id = "snow_dir_x", editor = "number", slider = true, default = 0, min = -1000, max = 1000, scale = 1000, help = "Snowfall direction X" }, |
|
{ category = "Snow", feature = "snow", name = "Snow direction Y", id = "snow_dir_y", editor = "number", slider = true, default = 0, min = -1000, max = 1000, scale = 1000, help = "Snowfall direction Y" }, |
|
{ category = "Snow", feature = "snow", name = "Snow direction Z", id = "snow_dir_z", editor = "number", slider = true, default = 1000, min = -1000, max = 1000, scale = 1000, help = "Snowfall direction Z" }, |
|
{ category = "Snow", feature = "snow", name = "Snow strength", id = "snow_str", editor = "number", slider = true, default = 0, min = 0, max = 1000, scale = 1000, help = "The constant snow strength" }, |
|
{ category = "Snow", feature = "snow", name = "Snow", id = "snow_enable", editor = "bool", default = false, }, |
|
|
|
{ category = "Wind", id = "wind", name = "Wind", editor = "preset_id", default = false, preset_class = "WindDef" }, |
|
|
|
{ category = "Heat Haze", id = "enable_heat_haze", name = "Enable Heat Haze", editor = "bool", default = false }, |
|
|
|
{ category = "Distance Blur and Desaturation", feature = "dist_blur_desat", name = "Blur", id = "pp_blur", min = 0, max = 100, default = 0, editor = "number",slider = true, help = "The intensity of the blur effect for distant objects." }, |
|
{ category = "Distance Blur and Desaturation", feature = "dist_blur_desat", name = "Blur distance", id = "pp_blur_distance", min = 0, max = 600, default = 0, editor = "number", slider = true, help = "The distance at which the distant objects start to get blurry." }, |
|
{ category = "Distance Blur and Desaturation", feature = "dist_blur_desat", name = "Desaturation", id = "pp_desaturation", min = 0, max = 100, default = 0, editor = "number", slider = true, help = "How intense is the desaturation of colors of the distant objects." }, |
|
{ category = "Distance Blur and Desaturation", feature = "dist_blur_desat", name = "Desaturation distance", id = "pp_desaturation_distance", min = 0, max = 600, default = 0, editor = "number", slider = true, help = "The distance at which the distant objects' colors get desaturated." }, |
|
|
|
{ category = "Exposure", feature = "autoexposure", id="_", editor="help", default=false, help = AutoExposureInstructions, buttons = {{name = "[On]", func = "AutoExposureOn"},{name = "[Off]", func = "AutoExposureOff"}, {name = "[Split]", func = "AutoExposureSplit"}, {name="[Debug]", func="AutoExposureDebugToggle"}} }, |
|
{ category = "Exposure", feature = "autoexposure", name = "Exposure", id = "exposure", min = -200, max = 200, default = 0, editor = "number" , slider = true, help = "The global exposure control in 1/100 EV. Intensity change is pow(2, E / 100)" }, |
|
{ category = "Exposure", feature = "autoexposure", name = "Auto Exposure (AE)", id="ae_key_bias", min = -3000000, max = 3000000, default = 0, scale = 1000000, editor = "number" , slider = true, help = "Exposure key value multiplier." }, |
|
{ category = "Exposure", feature = "autoexposure", name = "Scene lum min", id="ae_lum_min", min = -14*10000, max = 20*10000, default = -14*10000, scale = 10000, editor = "number" , slider = true, help = "Clamps average scene luminance.", no_edit = true }, |
|
{ category = "Exposure", feature = "autoexposure", name = "Scene lum max", id="ae_lum_max", min = -14*10000, max = 20*10000, default = 20*10000, scale = 10000, editor = "number" , slider = true, help = "Clamps average scene luminance.", no_edit = true }, |
|
{ category = "Exposure", feature = "autoexposure", name = "Adaptation speed bright",id="ae_adapt_speed_bright", min = 1, max = 1500, default = 500, scale = 100, editor = "number" , slider = true, help = "How fast the eye adapts to brighter scenes.", no_edit = true }, |
|
{ category = "Exposure", feature = "autoexposure", name = "Adaptation speed dark", id="ae_adapt_speed_dark", min = 1, max = 1500, default = 500, scale = 100, editor = "number" , slider = true, help = "How fast the eye adapts to darker scenes.", no_edit = true }, |
|
{ category = "Exposure", feature = "autoexposure", name = "AE Lum Min", id="ae_darkness_ign", min = 0, max = 99, default = 20, scale = "%", editor = "number" , slider = true, help = "From what percentage of the luminance of the scene to consider." }, |
|
{ category = "Exposure", feature = "autoexposure", name = "AE Lum Max", id="ae_brightness_ign", min = 1, max = 100, default = 95, scale = "%", editor = "number" , slider = true, help = "Until what percentage of the luminance of the scene to consider." }, |
|
{ category = "Exposure", feature = "autoexposure", name = "Use Constant Exposure", id="ae_disable", editor="bool", default=false, help = "Turn autoexposure on/off", }, |
|
|
|
{ category = "Bloom", feature = "hdr bloom", name = "Strength", id = "pp_bloom_strength", min = 0, max = 100, default = 0, scale = 100, editor = "number", slider = true, help = "How much Bloom affects the resulting picture." }, |
|
{ category = "Bloom", feature = "hdr bloom", name = "Threshold", id = "pp_bloom_threshold", min = 0, max = 100, default = 100, scale = 100, editor = "number", slider = true, help = "The luminance threshold after which colours bloom." }, |
|
{ category = "Bloom", feature = "hdr bloom", name = "Contrast", id = "pp_bloom_contrast", min = 0, max = 100, default = 0, scale = 100, editor = "number", slider = true, help = "The contrast of the final Bloom effect." }, |
|
{ category = "Bloom", feature = "hdr bloom", name = "Bloom colorization", id = "pp_bloom_colorization", min = 0, max = 100, scale = 100, default = 30, editor = "number", slider = true, help = "The mixing ratio between the original Bloom color and the tint." }, |
|
{ category = "Bloom", feature = "hdr bloom", name = "Inner tint", id = "pp_bloom_inner_tint", default = RGB(180, 180, 180), editor = "color", help = "Bloom effect's inner tint." }, |
|
{ category = "Bloom", feature = "hdr bloom", name = "Outer tint", id = "pp_bloom_outer_tint", default = RGB(180, 180, 180), editor = "color", help = "Bloom effect's outer tint." }, |
|
{ category = "Bloom", feature = "hdr bloom", name = "Mip2 radius", id = "pp_bloom_mip2_radius" , min = 1, max = 64, default = 16, editor = "number", slider = true, help = "Gauss blur radius for mip2." }, |
|
{ category = "Bloom", feature = "hdr bloom", name = "Mip3 radius", id = "pp_bloom_mip3_radius" , min = 4, max = 64, default = 16, editor = "number", slider = true, help = "Gauss blur radius for mip3." }, |
|
{ category = "Bloom", feature = "hdr bloom", name = "Mip4 radius", id = "pp_bloom_mip4_radius" , min = 8, max = 64, default = 32, editor = "number", slider = true, help = "Gauss blur radius for mip4." }, |
|
{ category = "Bloom", feature = "hdr bloom", name = "Mip5 radius", id = "pp_bloom_mip5_radius" , min = 8, max = 64, default = 32, editor = "number", slider = true, help = "Gauss blur radius for mip5." }, |
|
{ category = "Bloom", feature = "hdr bloom", name = "Mip6 radius", id = "pp_bloom_mip6_radius" , min = 8, max = 64, default = 32, editor = "number", slider = true, help = "Gauss blur radius for mip6." }, |
|
|
|
{ category = "Exposure", name = "Emissive Boost", id = "emissive_boost", min = 100, max = 10000, default = 100, scale = 10000, editor = "number", slider = true }, |
|
{ category = "Exposure", name = "Particle Exposure Additive", id = "ps_exposure", min = -1000, max = 1000, default = 0, editor = "number" , slider = true, help = "EV Control in 1/100 EV to adjust particle brightness when blending. Intensity change is pow(2, E / 100)" }, |
|
|
|
{ category = "Other", name = "AO texture darkness", id = "ao_lower_limit", editor = "number", slider = true, min = 0, max = 255, default = 0, scale = 255, help = "Fits the values of the Ambient Occlusion Map of all meshes in a new range that has the specified minimum value." }, |
|
{ category = "Other", name = "SSAO strength", id = "pp_ssao_strength", min = 0, max = 200, editor = "number" , slider = true, default = 0, scale = 100, help = "The intensity of Screen-Space Ambient Occlusion in percents." }, |
|
|
|
{ category = "Other", feature = "three_point_lighting", name = "Three Point Lighting", id = "three_point_lighting", editor = "preset_id", default = "", preset_class = "ThreePointLighting" }, |
|
{ category = "Other", feature = "Unit_Lighting", name = "Unit Lighting Strength", id = "unit_lighting_strength", editor = "number", slider = true, min = 0, max = 100, default = 50, scale = 100, help = "The intensity of the Unit Lighting effect." }, |
|
{ category = "Other", feature = "Unit_Lighting", name = "Unit Lighting Contrast", id = "unit_lighting_contrast", editor = "number", slider = true, min = 0, max = 100, default = 0, scale = 100, help = "The contrast strength of the Unit Lighting effect." }, |
|
|
|
{ category = "Lights", name = "Light Shadows", id = "light_shadows", editor = "number", slider = true, min = 0, max = 1000, scale = 1000, default = 1000, feature = "shadow", help = "Shadows from lights strength." }, |
|
{ category = "Lights", name = "LightColorA", id = "lightcolor1", editor = "color", default = RGB(255, 255, 255), alpha = false, help = "This color can be used by point&spot lights." }, |
|
{ category = "Lights", name = "LightColorB", id = "lightcolor2", editor = "color", default = RGB(255, 255, 255), alpha = false, help = "This color can be used by point&spot lights." }, |
|
{ category = "Lights", name = "LightColorC", id = "lightcolor3", editor = "color", default = RGB(255, 255, 255), alpha = false, help = "This color can be used by point&spot lights." }, |
|
{ category = "Lights", name = "LightColorD", id = "lightcolor4", editor = "color", default = RGB(255, 255, 255), alpha = false, help = "This color can be used by point&spot lights." }, |
|
{ category = "Lights", feature = "night", name = "Night Lights", id = "night", blend = const.NightBlendThreshold, editor = "bool", default = false, help = "Determines whether the lights should be switched on or off." }, |
|
}, |
|
} |
|
|
|
DefineClass.LightmodelPreset = { |
|
__parents = { "Preset", "Lightmodel" }, |
|
|
|
GlobalMap = "LightmodelPresets", |
|
GedEditor = "LightmodelEditor", |
|
EditorMenubarName = "Lightmodels", |
|
EditorMenubar = "Editors.Art", |
|
EditorShortcut = "Ctrl-M", |
|
EditorIcon = "CommonAssets/UI/Icons/bulb ecology energy lamp light power.png", |
|
ValidateAfterSave = true, |
|
PropertyTabs = { |
|
{ TabName = "Preset", Categories = { Preset = true }, }, |
|
{ TabName = "Sun", Categories = { Sun = true, ["Sun Path"] = true, ["Sun Pos"] = true, } }, |
|
{ TabName = "Sky", Categories = { Sky = true, ["Night Sky"] = true, ["Env Capture"] = true, ["Cubemap"] = true, } }, |
|
{ TabName = "Weather", Categories = { Fog = true, Rain = true, Clouds = true, ["Cloud shadows"] = true, ["Wind"] = true, } }, |
|
{ TabName = "Environment", Categories = { Water = true, Snow = true, Ice = true, Frost = true, } }, |
|
{ TabName = "Effects", Categories = { Exposure = true, Bloom = true, Other = true, Vignette = true, ["Chromatic Aberration"] = true, ["Color Grading"] = true, Lights = true, } }, |
|
} |
|
} |
|
|
|
DefineClass.SHDiffuseIrradiance = { |
|
__parents = { "Preset" }, |
|
properties = { |
|
{ name = "SH9 Coefficients", id = "sh9_coefficients", editor = "text", default = "", read_only = true }, |
|
}, |
|
EditorMenubarName = "", |
|
EditorMenubar = false, |
|
} |
|
|
|
function DoSetLightmodel(view, lm_buf, time, start_offset) |
|
if view < 1 or view > camera.GetViewCount() then return end |
|
start_offset = start_offset or 0 |
|
|
|
SetSceneParam(view, "UseTimeOfDay", lm_buf.use_time_of_day and 1 or 0, 0, start_offset) |
|
if not lm_buf.use_time_of_day then |
|
local prev_azi = (GetSceneParam(view, "SunWidth") / 1000 + 360) % 360 |
|
local azi = (lm_buf.sun_azi + mapdata.MapOrientation) % 360 |
|
if abs(azi - prev_azi) > 180 then |
|
if azi > 180 then |
|
prev_azi = prev_azi + 360 |
|
else |
|
azi = azi + 360 |
|
end |
|
end |
|
SetSceneParam(view, "SunWidth", prev_azi * 1000, 0, start_offset) |
|
SetSceneParam(view, "SunWidth", azi * 1000, time, start_offset) |
|
SetSceneParam(view, "SunHeight", lm_buf.sun_alt * 100, time, start_offset) |
|
if lm_buf.sky_custom_sun then |
|
SetSceneParam(view, "SkySunAzi", lm_buf.sky_custom_sun_azi * 1000, time, start_offset) |
|
SetSceneParam(view, "SkySunAlt", lm_buf.sky_custom_sun_alt * 100, time, start_offset) |
|
else |
|
SetSceneParam(view, "SkySunAzi", -1, 0, 0) |
|
SetSceneParam(view, "SkySunAlt", -1, 0, 0) |
|
end |
|
SetSceneParam(view, "SunShadowHeight", lm_buf.sun_shadow_height * 100, time, start_offset) |
|
end |
|
|
|
SetSceneParam(view, "Shadow", lm_buf.shadow, time, start_offset) |
|
if lm_buf.shadow then |
|
SetSceneParam(view, "ShadowRange", lm_buf.shadow_range, time, start_offset) |
|
end |
|
|
|
SetSceneParamColor(view, "MieCoefs", lm_buf.mie_coefs, time, start_offset) |
|
SetSceneParamColor(view, "RayCoefs", lm_buf.ray_coefs, time, start_offset) |
|
SetSceneParam(view, "MieSH", lm_buf.mie_sh, time, start_offset) |
|
SetSceneParam(view, "RaySH", lm_buf.ray_sh, time, start_offset) |
|
SetSceneParam(view, "MieMC", lm_buf.mie_mc, time, start_offset) |
|
SetSceneParam(view, "SkyExp", lm_buf.sky_exp, time, start_offset) |
|
SetSceneParamColor(view, "SunDiffuseColor", lm_buf.sun_diffuse_color, time, start_offset, false) |
|
SetSceneParam(view, "SunIntensity", lm_buf.sun_intensity, time, start_offset) |
|
|
|
SetSceneParam(view, "StarsIntensity", lm_buf.stars_intensity, time, start_offset) |
|
SetSceneParam(view, "StarsBlueTint", lm_buf.stars_blue_tint, time, start_offset) |
|
SetSceneParam(view, "StarsRotation", lm_buf.stars_rotation, time, start_offset) |
|
SetSceneParam(view, "StarsPoleAlt", lm_buf.stars_pole_alt, time, start_offset) |
|
SetSceneParam(view, "StarsPoleAzi", lm_buf.stars_pole_azi, time, start_offset) |
|
SetSceneParam(view, "MilkyWayIntensity", lm_buf.mw_intensity, time, start_offset) |
|
SetSceneParam(view, "MilkyWayBlueTint", lm_buf.mw_blue_tint, time, start_offset) |
|
|
|
SetSceneParam(view, "SunAngularRadius", lm_buf.sun_angular_radius, time, start_offset) |
|
SetSceneParam(view, "GlobalExposure", lm_buf.exposure, time, start_offset) |
|
SetSceneParam(view, "EmissiveBoost", lm_buf.emissive_boost, time, start_offset) |
|
SetSceneParam(view, "ExtEnvExposure", lm_buf.ext_env_exposure, time, start_offset) |
|
SetSceneParam(view, "IntEnvExposure", lm_buf.int_env_exposure, time, start_offset) |
|
SetSceneParam(view, "ParticleExposure", lm_buf.ps_exposure, time, start_offset) |
|
|
|
SetSceneParamColor(view, "FogColor", lm_buf.fog_color, time, start_offset) |
|
SetSceneParam(view, "FogGlobalDensity", lm_buf.fog_density, time, start_offset) |
|
SetSceneParam(view, "FogHeightFalloff", lm_buf.fog_height_falloff, time, start_offset) |
|
SetSceneParam(view, "FogStart", lm_buf.fog_start, time, start_offset) |
|
|
|
SetIceStrength(lm_buf.ice_strength, "Lightmodel", view, time, start_offset) |
|
SetSceneParamColor(view, "IceColor", lm_buf.ice_color, time, start_offset) |
|
SetSceneParamColor(view, "SnowColor", lm_buf.snow_color, time, start_offset) |
|
|
|
SetSceneParam(view, "SnowDirX", lm_buf.snow_dir_x, time, start_offset) |
|
SetSceneParam(view, "SnowDirY", lm_buf.snow_dir_y, time, start_offset) |
|
SetSceneParam(view, "SnowDirZ", lm_buf.snow_dir_z, time, start_offset) |
|
SetSceneParam(view, "SnowStr", lm_buf.snow_str, time, start_offset) |
|
|
|
SetSceneParamColor(view, "WaterColor", lm_buf.water_color, time, start_offset) |
|
SetSceneParam(view, "AbsorptionCoef", lm_buf.absorption_coef, time, start_offset) |
|
SetSceneParam(view, "MinimumDepth", lm_buf.minimum_depth, time, start_offset) |
|
|
|
SetSceneParam(view, "AutoExposureKeyBias", lm_buf.ae_key_bias, time, start_offset) |
|
SetSceneParam(view, "AutoExposureLumMin", lm_buf.ae_lum_min, time, start_offset) |
|
SetSceneParam(view, "AutoExposureLumMax", lm_buf.ae_lum_max, time, start_offset) |
|
SetSceneParam(view, "AutoExposureAdaptSpeedBright", lm_buf.ae_adapt_speed_bright, time, start_offset) |
|
SetSceneParam(view, "AutoExposureAdaptSpeedDark", lm_buf.ae_adapt_speed_dark, time, start_offset) |
|
SetSceneParam(view, "AutoExposureBrightnessIgnorance", 100 - lm_buf.ae_brightness_ign, time, start_offset) |
|
SetSceneParam(view, "AutoExposureDarknessIgnorance", lm_buf.ae_darkness_ign, time, start_offset) |
|
SetSceneParam(view, "AutoExposureDisable", lm_buf.ae_disable and 1 or 0, time, start_offset) |
|
|
|
if not config.LightModelUnusedFeatures["dist_blur_desat"] then |
|
SetSceneParamVector(view, "PostProc", 0, lm_buf.pp_blur, time, start_offset) |
|
SetSceneParamVector(view, "PostProc", 1, lm_buf.pp_desaturation, time, start_offset) |
|
SetSceneParamVector(view, "PostProc", 2, lm_buf.pp_blur_distance, time, start_offset) |
|
SetSceneParamVector(view, "PostProc", 3, lm_buf.pp_desaturation_distance, time, start_offset) |
|
end |
|
|
|
SetSceneParamColor(view, "BloomInnerTint", lm_buf.pp_bloom_inner_tint, time, start_offset) |
|
SetSceneParamColor(view, "BloomOuterTint", lm_buf.pp_bloom_outer_tint, time, start_offset) |
|
SetSceneParamVector(view, "Bloom", 0, lm_buf.pp_bloom_strength, time, start_offset) |
|
SetSceneParamVector(view, "Bloom", 1, lm_buf.pp_bloom_threshold, time, start_offset) |
|
SetSceneParamVector(view, "Bloom", 2, lm_buf.pp_bloom_contrast, time, start_offset) |
|
SetSceneParamVector(view, "Bloom", 3, lm_buf.pp_bloom_colorization, time, start_offset) |
|
SetSceneParamVector(view, "BloomRadii", 0, lm_buf.pp_bloom_mip2_radius, time, start_offset) |
|
SetSceneParamVector(view, "BloomRadii", 1, lm_buf.pp_bloom_mip3_radius, time, start_offset) |
|
SetSceneParamVector(view, "BloomRadii", 2, lm_buf.pp_bloom_mip4_radius, time, start_offset) |
|
SetSceneParamVector(view, "BloomRadii", 3, lm_buf.pp_bloom_mip5_radius, time, start_offset) |
|
SetSceneParamVector(view, "BloomRadii", 4, lm_buf.pp_bloom_mip6_radius, time, start_offset) |
|
|
|
SetSceneParamVector(view, "AOLowerLimit", 0, lm_buf.ao_lower_limit, time, start_offset) |
|
SetSceneParamVector(view, "SSAO", 0, lm_buf.pp_ssao_strength, time, start_offset) |
|
|
|
SetPostProcPredicate("heat_haze", lm_buf.enable_heat_haze) |
|
|
|
if not config.LightModelUnusedFeatures["three_point_lighting"] then |
|
if lm_buf.three_point_lighting ~= "" then |
|
Presets.ThreePointLighting.ThreePointLightingRenderVars[lm_buf.three_point_lighting]:Apply() |
|
table.change_base(hr, { EnableThreePointLighting = 1 }) |
|
else |
|
table.change_base(hr, { EnableThreePointLighting = 0 }) |
|
end |
|
end |
|
|
|
|
|
if lm_buf.exterior_envmap and lm_buf.exterior_envmap ~= "" then |
|
local exterior_sh = Presets.SHDiffuseIrradiance.Default[lm_buf.exterior_envmap .. "Exterior"] |
|
if not exterior_sh then print("once", "Lightmodel", lm_buf.exterior_envmap .. "Exterior", "needs to be recaptured!") end |
|
local err = SetCubemap(view, string.format("Textures/Cubemaps/%sExterior", lm_buf.exterior_envmap), exterior_sh and Decode64(exterior_sh.sh9_coefficients) or "", 0, time, start_offset) |
|
if err then |
|
print("SetCubemap failed", err) |
|
end |
|
end |
|
if lm_buf.interior_envmap and lm_buf.interior_envmap ~= "" then |
|
local interior_sh = Presets.SHDiffuseIrradiance.Default[lm_buf.interior_envmap .. "Interior"] |
|
if not interior_sh then print("once", "Lightmodel", lm_buf.interior_envmap .. "Interior", "needs to be recaptured!") end |
|
local err = SetCubemap(view, string.format("Textures/Cubemaps/%sInterior", lm_buf.interior_envmap), interior_sh and Decode64(interior_sh.sh9_coefficients) or "", 1, time, start_offset) |
|
if err then |
|
print("SetCubemap failed", err) |
|
end |
|
end |
|
|
|
SetSceneParam(view, "LightShadows", lm_buf.light_shadows, time, start_offset) |
|
|
|
SetSceneParam(view, "GameSpecificData0", lm_buf.unit_lighting_strength, time, start_offset) |
|
SetSceneParam(view, "GameSpecificData1", lm_buf.unit_lighting_contrast, time, start_offset) |
|
|
|
for i = 1, 4 do |
|
SetSceneParamColor(view, "LightColor" .. i, lm_buf["lightcolor" .. i], time, start_offset) |
|
end |
|
|
|
Msg("LightmodelSetSceneParams", view, lm_buf, time, start_offset) |
|
end |
|
|
|
MapVar("CurrentLightmodel", {}) |
|
MapVar("LastSetLightmodel", {}) |
|
|
|
if FirstLoad then |
|
LightmodelOverride = false |
|
end |
|
|
|
function GetEnvMapsList(site) |
|
local maps = { "" } |
|
for _,v in ipairs(io.listfiles("Textures/Cubemaps")) do |
|
local map = string.match(v, "Textures/Cubemaps/(.*)" .. site .. "Env%.dds") |
|
if map then |
|
maps[#maps + 1] = map |
|
end |
|
end |
|
table.sort(maps) |
|
return maps |
|
end |
|
|
|
function PreloadLightmodelCubemaps(lightmodel) |
|
if not lightmodel or lightmodel == "" then |
|
return |
|
end |
|
|
|
local lm_buf = LightmodelPresets[lightmodel] |
|
if not lm_buf then |
|
return |
|
end |
|
|
|
local function preload_path(path) |
|
local image_id = ResourceManager.GetResourceID(path) |
|
if image_id == const.InvalidResourceID then |
|
printf("once", "Could not load image %s!", path or "") |
|
return |
|
end |
|
|
|
local image = AsyncGetResource(image_id) |
|
return image |
|
end |
|
local exterior_map = string.format("Textures/Cubemaps/%sExterior", lm_buf.exterior_envmap) |
|
local interior_map = string.format("Textures/Cubemaps/%sInterior", lm_buf.interior_envmap) |
|
|
|
local result = { |
|
Done = function(self) |
|
if self.exterior_specular then self.exterior_specular:ReleaseRef() end |
|
if self.interior_specular then self.interior_specular:ReleaseRef() end |
|
end, |
|
exterior_specular = preload_path(exterior_map .. "Specular"), |
|
interior_specular = preload_path(interior_map .. "Specular"), |
|
} |
|
return result |
|
end |
|
|
|
function SetLightmodelOverride(view, lightmodel) |
|
view = view or 1 |
|
lightmodel = LightmodelPresets[lightmodel] or lightmodel |
|
lightmodel = type(lightmodel) == "table" and lightmodel or false |
|
if LightmodelOverride ~= lightmodel then |
|
LightmodelOverride = lightmodel |
|
SetLightmodel(view, LastSetLightmodel and LastSetLightmodel[1] or lightmodel, 0, "from_override") |
|
end |
|
end |
|
|
|
function SetLightmodel(view, lightmodel, time, from_override) |
|
if not CurrentLightmodel then return end |
|
view = view or 1 |
|
time = time or 0 |
|
lightmodel = LightmodelPresets[lightmodel] or lightmodel |
|
if type(lightmodel) ~= "table" then |
|
if type(lightmodel) == "string" then |
|
assert(false, "lightmodel not found: " .. tostring(lightmodel)) |
|
end |
|
lightmodel = LightmodelPresets.ArtPreview |
|
end |
|
if view < 1 or view > camera.GetViewCount() then return end |
|
if LastSetLightmodel then |
|
LastSetLightmodel[view] = lightmodel |
|
end |
|
lightmodel = LightmodelOverride or lightmodel |
|
local prev_lm = CurrentLightmodel[view] |
|
if prev_lm and not IsKindOf(prev_lm, "LightmodelPreset") then |
|
setmetatable(prev_lm, LightmodelPreset) |
|
end |
|
CurrentLightmodel[view] = lightmodel |
|
|
|
hr.TODForceTime = -1 |
|
local override = LightmodelOverride == lightmodel |
|
if override then |
|
if lightmodel.use_time_of_day then |
|
hr.TODForceTime = LocalToEarthTime(lightmodel.time*1000) |
|
end |
|
end |
|
|
|
|
|
Msg("LightmodelChange", view, lightmodel, time, prev_lm, from_override) |
|
DoSetLightmodel(view, lightmodel, time) |
|
Msg("AfterLightmodelChange", view, lightmodel, time, prev_lm, from_override) |
|
end |
|
|
|
do |
|
local unused_features = config.LightModelUnusedFeatures or empty_table |
|
for _, prop in ipairs(Lightmodel.properties) do |
|
if prop.feature and unused_features[prop.feature] then |
|
prop.no_edit = true |
|
end |
|
end |
|
end |
|
|
|
function LightmodelPreset:ListEquivalentLMs(root, prop_id, ged, param) |
|
local feature = string.match(prop_id, "preset_(.+)") |
|
local list = LightmodelEquivalenceByValue(self, feature) |
|
ged:ShowMessage("Equivalent Lightmodels", table.concat(list, "\n")) |
|
end |
|
|
|
function LightmodelPreset:SetFeaturePreset(ref_preset) |
|
if not ref_preset then return end |
|
local feature = ref_preset.group |
|
if not feature then return end |
|
local feature_data = LightmodelFeatureToProperties[feature] |
|
for _, prop in ipairs(feature_data) do |
|
self:SetProperty(prop.id, ref_preset:GetProperty(prop.id)) |
|
end |
|
end |
|
|
|
function LightmodelPreset:SetFeaturePresetId(feature, feature_preset_id) |
|
local presets = Presets.LightmodelFeaturePreset or empty_table |
|
local feature_group = presets[feature] or empty_table |
|
self:SetFeaturePreset(feature_group[feature_preset_id]) |
|
end |
|
|
|
local function EarlyClassDescendants(classdefs, target_class, callback) |
|
local cache = {} |
|
|
|
local function EarlyIsKindOf(obj_class, target_class) |
|
local cache_hit = cache[obj_class] |
|
if cache_hit ~= nil then |
|
return cache_hit |
|
end |
|
|
|
if obj_class == target_class then |
|
cache[obj_class] = true |
|
return true |
|
end |
|
local class = classdefs[obj_class] |
|
for _, parent in ipairs(class and class.__parents) do |
|
if(EarlyIsKindOf(parent, target_class)) then |
|
return true |
|
end |
|
end |
|
cache[obj_class] = false |
|
return false |
|
end |
|
|
|
|
|
for class_name in pairs(classdefs) do |
|
if EarlyIsKindOf(class_name, target_class) then |
|
callback(class_name, classdefs[class_name]) |
|
end |
|
end |
|
end |
|
|
|
function OnMsg.ClassesGenerate(classdefs) |
|
LightmodelFeatureToProperties = {} |
|
|
|
local properties = {} |
|
EarlyClassDescendants(classdefs, "LightmodelPart", function(class_name, classdef) |
|
local classProperties = {} |
|
|
|
if classdef.GetLightmodelProperties then |
|
classdef:GetLightmodelProperties(classProperties) |
|
else |
|
table.iappend(classProperties, classdef.properties) |
|
end |
|
|
|
local uses_preset = function(chain_func) |
|
return function(self, ...) |
|
local preset_id = "preset_" .. classdef.lightmodel_feature |
|
local uses_preset = self[preset_id] and self[preset_id] ~= "" |
|
if uses_preset then return uses_preset end |
|
if type(chain_func) == "function" then return chain_func(self, ...) end |
|
if chain_func then return chain_func end |
|
return false |
|
end |
|
end |
|
for k, prop in ipairs(classProperties) do |
|
if not prop.category then |
|
prop.category = classdef.lightmodel_category |
|
end |
|
if not prop.feature then |
|
prop.feature = classdef.lightmodel_feature |
|
end |
|
local lm_prop = table.copy(prop) |
|
lm_prop.dont_save = uses_preset(lm_prop.dont_save) |
|
lm_prop.read_only = uses_preset(lm_prop.read_only) |
|
properties[#properties + 1] = lm_prop |
|
|
|
for _,button in ipairs(lm_prop.buttons or empty_table) do |
|
if not Lightmodel[button.func] and classdef[button.func] then |
|
Lightmodel[button.func] = classdef[button.func] |
|
elseif Lightmodel[button.func] and not classdef[button.func] then |
|
classdef[button.func] = Lightmodel[button.func] |
|
end |
|
end |
|
end |
|
end) |
|
|
|
for _, prop in ipairs(properties) do |
|
local feature = prop.feature |
|
if feature then |
|
local feature_list = LightmodelFeatureToProperties[feature] |
|
if not feature_list then |
|
feature_list = {} |
|
LightmodelFeatureToProperties[feature] = feature_list |
|
end |
|
table.insert(feature_list, prop) |
|
end |
|
end |
|
|
|
|
|
for feature, feature_data in pairs(LightmodelFeatureToProperties) do |
|
local preset_feature_prop_id = "preset_" .. feature |
|
feature_data.preset_feature_prop_id = preset_feature_prop_id |
|
table.insert(Lightmodel.properties, { |
|
id = preset_feature_prop_id, |
|
editor = "preset_id", |
|
preset_class = "LightmodelFeaturePreset", |
|
preset_group = feature, |
|
default = "", |
|
category = (feature_data[1] or empty_table).category, |
|
buttons = {{ name = "List", func = "ListEquivalentLMs"}} |
|
}) |
|
|
|
table.iappend(Lightmodel.properties, feature_data) |
|
end |
|
end |
|
|
|
function OnMsg.DataLoaded() |
|
for _, lm in pairs(LightmodelPresets) do |
|
for feature, data in pairs(LightmodelFeatureToProperties) do |
|
local preset_id = lm:GetProperty(data.preset_feature_prop_id) |
|
lm:SetFeaturePresetId(feature, preset_id) |
|
end |
|
end |
|
end |
|
|
|
local lightmodel_properties |
|
function OnMsg.ClassesBuilt() |
|
lightmodel_properties = {} |
|
local preset = LightmodelPreset |
|
for _, prop_meta in ipairs(preset:GetProperties()) do |
|
if prop_meta.category ~= "Preset" and not prop_eval(prop_meta.no_edit, preset, prop_meta) and not prop_eval(prop_meta.read_only, preset, prop_meta)then |
|
lightmodel_properties[#lightmodel_properties + 1] = prop_meta |
|
end |
|
end |
|
end |
|
|
|
|
|
function BlendLightmodels(result, lm1, lm2, num, denom) |
|
SuspendObjModified("BlendLightmodels") |
|
local firstHalf = 2*num < denom |
|
for _, prop_meta in ipairs(lightmodel_properties) do |
|
local prop_id = prop_meta.id |
|
local v1 = lm1:GetProperty(prop_id) |
|
local v2 = lm2:GetProperty(prop_id) |
|
local value |
|
local prop_blend = prop_meta.blend |
|
if num >= denom or v1 == v2 or prop_blend == "set" then |
|
value = v2 |
|
elseif num <= 0 or prop_blend == "suppress" then |
|
value = v1 |
|
else |
|
value = v2 |
|
local prop_editor = prop_meta.editor |
|
if prop_editor == "number" or prop_editor == "point" then |
|
value = Lerp(v1, v2, num, denom) |
|
elseif prop_editor == "color" then |
|
value = InterpolateRGB(v1, v2, num, denom) |
|
elseif type(prop_blend) == "number" and prop_blend ~= 50 then |
|
|
|
if prop_editor == "bool" then |
|
value = v1 and 100 * num < prop_blend * denom or v2 and 100 * num >= (100 - prop_blend) * denom |
|
elseif 100 * num < prop_blend * denom then |
|
value = v1 |
|
end |
|
elseif firstHalf then |
|
value = v1 |
|
end |
|
end |
|
result:SetProperty(prop_id, value) |
|
end |
|
ResumeObjModified("BlendLightmodels") |
|
end |
|
|
|
function LightmodelPreset:GetInteriorEnvmapImage() |
|
return "Textures/Cubemaps/Thumbnails/" .. self.interior_envmap .. "Interior.jpg" |
|
end |
|
|
|
function LightmodelPreset:GetExteriorEnvmapImage() |
|
return "Textures/Cubemaps/Thumbnails/" .. self.exterior_envmap .. "Exterior.jpg" |
|
end |
|
|
|
function LightmodelPreset:Sethdr_pano(value) |
|
self.hdr_pano = value |
|
end |
|
|
|
local function AppendDefaultExtension(path, default_extension) |
|
if path and path ~= "" then |
|
local _, _, extension = SplitPath(path) |
|
if not extension or extension == "" then |
|
path = path .. default_extension |
|
end |
|
end |
|
return path |
|
end |
|
|
|
if Platform.developer then |
|
function LightmodelPreset:Setsky_custom_sun(b) |
|
self.sky_custom_sun = b |
|
if b then |
|
self.sky_custom_sun_alt = self.sun_alt |
|
self.sky_custom_sun_azi = self.sun_azi |
|
else |
|
self.sky_custom_sun_alt = 0 |
|
self.sky_custom_sun_azi = 180 |
|
end |
|
ObjModified(self) |
|
end |
|
end |
|
|
|
function LightmodelPreset:Setuse_time_of_day(b) |
|
self.use_time_of_day = b |
|
ObjModified(self) |
|
end |
|
|
|
function LightmodelPreset:Setshadow(b) |
|
self.shadow = b |
|
ObjModified(self) |
|
end |
|
|
|
function LightmodelPreset:Setae_brightness_ign(b) |
|
self.ae_brightness_ign = b |
|
if (self.ae_brightness_ign - self.ae_darkness_ign <= 1) then |
|
self.ae_darkness_ign = self.ae_brightness_ign - 1 |
|
end |
|
end |
|
|
|
function LightmodelPreset:Setae_darkness_ign(b) |
|
self.ae_darkness_ign = b |
|
if (self.ae_brightness_ign - self.ae_darkness_ign <= 1) then |
|
self.ae_brightness_ign = self.ae_darkness_ign + 1 |
|
end |
|
end |
|
|
|
function LightmodelPreset:Getsun_earthtime_info() |
|
local sunrise = hr.TODSunriseTime |
|
local sunset = hr.TODSunsetTime |
|
local noon = sunrise + (sunset - sunrise) / 2 |
|
return string.format("Sunrise %02d:%02d Noon %02d:%02d Sunset %02d:%02d", |
|
sunrise / 60, sunrise % 60, |
|
noon / 60, noon % 60, |
|
sunset / 60, sunset % 60 |
|
) |
|
end |
|
|
|
function LightmodelPreset:Getsunrise_time() return EarthToLocalTime(hr.TODSunriseTime) end |
|
function LightmodelPreset:Getsunrise_azi() return hr.TODSunriseAzi end |
|
function LightmodelPreset:Getsunset_time() return EarthToLocalTime(hr.TODSunsetTime) end |
|
function LightmodelPreset:Getsunset_azi() return hr.TODSunsetAzi end |
|
function LightmodelPreset:Getsun_max_elevation() return hr.TODSunMaxElevation end |
|
|
|
function LightmodelPreset:Getsun_shadow_min() return hr.TODSunShadowMinAltitude end |
|
function LightmodelPreset:Setsun_shadow_min(v) hr.TODSunShadowMinAltitude = v end |
|
|
|
function LightmodelPreset:Getsun_nr() return hr.TODNorthRotation end |
|
function LightmodelPreset:Setsun_nr(v) hr.TODNorthRotation = v end |
|
|
|
function LightmodelPreset:Setsunrise_time(v) |
|
hr.TODSunriseTime = LocalToEarthTime(v) |
|
ObjModified(self) |
|
end |
|
function LightmodelPreset:Setsunrise_azi(v) |
|
hr.TODSunriseAzi = v |
|
ObjModified(self) |
|
end |
|
function LightmodelPreset:Setsunset_time(v) |
|
hr.TODSunsetTime = LocalToEarthTime(v) |
|
ObjModified(self) |
|
end |
|
function LightmodelPreset:Setsunset_azi(v) |
|
hr.TODSunsetAzi = v |
|
ObjModified(self) |
|
end |
|
function LightmodelPreset:Setsun_max_elevation(v) |
|
hr.TODSunMaxElevation = v |
|
ObjModified(self) |
|
end |
|
|
|
function LightmodelPreset:Settime(v) |
|
self.time = v |
|
if hr.TODForceTime >= 0 then |
|
hr.TODForceTime = LocalToEarthTime(self.time*1000) |
|
end |
|
end |
|
|
|
function LightmodelPreset:GetListName() |
|
return self.group |
|
end |
|
|
|
function LightmodelPreset:Gettime_next(v) |
|
local list_name = self:GetListName() |
|
local next_lm = FindNextLightmodel(list_name, self.time+1) |
|
if not next_lm then return "" end |
|
return string.format("%02d:%02d (%s)", next_lm.time / 60, next_lm.time % 60, next_lm.id) |
|
end |
|
|
|
function LightmodelPreset:PreviewStart() |
|
if not self:EditorCheck(true) then return end |
|
|
|
SetLightmodelOverride(1, self.id) |
|
hr.TODForceTime = LocalToEarthTime(self.time*1000) |
|
end |
|
|
|
function LightmodelPreset:PreviewEnd() |
|
if not self:EditorCheck(true) then return end |
|
|
|
local list_name = self:GetListName() |
|
local next_lm = FindNextLightmodel(list_name, self.time+1) |
|
SetLightmodelOverride(1, self.id) |
|
hr.TODForceTime = LocalToEarthTime(next_lm.time*1000) |
|
end |
|
|
|
function LightmodelPreset:PreviewBlendStart() |
|
if not self:EditorCheck(true) then return end |
|
|
|
local list_name = self:GetListName() |
|
local prev_lm = FindPrevLightmodel(list_name, self.time - 1) |
|
SetLightmodelOverride(1, prev_lm.id) |
|
hr.TODForceTime = LocalToEarthTime(self.time*1000) |
|
end |
|
|
|
function LightmodelPreset:PreviewBlendEnd() |
|
if not self:EditorCheck(true) then return end |
|
|
|
SetLightmodelOverride(1, self.id) |
|
hr.TODForceTime = LocalToEarthTime((self.time + self.blend_time)*1000) |
|
end |
|
|
|
function LightmodelPreset:PreviewBlend() |
|
if IsEditorActive() then |
|
print("Lightmodel blending preview works only outside the in-game editor!") |
|
return |
|
end |
|
if not self:EditorCheck(true) then return end |
|
|
|
CreateRealTimeThread(function() |
|
local list_name = self:GetListName() |
|
local prev_lm = FindPrevLightmodel(list_name, self.time - 1) |
|
CancelRendering() |
|
SetLightmodelOverride(1, false) |
|
SetLightmodel(1, prev_lm.id, 0) |
|
Sleep(50) |
|
ResumeRendering() |
|
local start_time = LocalToEarthTime(self.time*1000) |
|
local end_time = LocalToEarthTime((self.time+self.blend_time)*1000) |
|
hr.TODForceTime = start_time |
|
Sleep(1000) |
|
local blend_time = MulDivRound(self.blend_time, const.HourDuration, 60) |
|
SetLightmodel(1, self.id, blend_time) |
|
local step = MulDivRound(60*1000, 10, const.HourDuration) |
|
CreateGameTimeThread(function() |
|
for time = start_time, end_time, step do |
|
hr.TODForceTime = time |
|
Sleep(10) |
|
end |
|
self:PreviewBlendEnd(self) |
|
end) |
|
end) |
|
end |
|
|
|
function LightmodelsCombo() |
|
return table.keys2(LightmodelPresets, true, "") |
|
end |
|
|
|
DefineConstInt("Disaster", "LightningHorizontalMaxDistance", 600, "m") |
|
DefineConstInt("Disaster", "LightningHorizontalMinDistance", 300, "m") |
|
DefineConstInt("Disaster", "LightningVerticalMaxDistance", 600, "m") |
|
DefineConstInt("Disaster", "LightningVerticalMinDistance", 300, "m") |
|
|
|
function WaitLightingStrike(view) |
|
local lm = CurrentLightmodel[view] |
|
if not lm or not lm.lightning_enable then |
|
return |
|
end |
|
Sleep(AsyncRand(lm.lightning_interval_min, lm.lightning_interval_max)) |
|
lm = CurrentLightmodel[view] |
|
if not lm or not lm.lightning_enable then |
|
return |
|
end |
|
local eye, lookat, _, _, _, fov = GetCamera() |
|
if AsyncRand(100) < lm.lightning_strike_chance then |
|
local disaster = const.Disaster |
|
local min, max, lightning_fx |
|
if AsyncRand(100) < lm.lightning_vertical_chance then |
|
min, max, lightning_fx = disaster.LightningVerticalMinDistance, disaster.LightningVerticalMaxDistance, "LightningFarVertical" |
|
else |
|
min, max, lightning_fx = disaster.LightningHorizontalMinDistance, disaster.LightningHorizontalMaxDistance, "LightningFarHorizontal" |
|
end |
|
local fov_safe_area = 20 * 60 |
|
fov = Max(Min(fov + fov_safe_area, 360 * 60), 0) |
|
local rot_angle_in_frustum = AsyncRand(fov) - DivRound(fov, 2) + camera.GetYaw() |
|
local rot_radius = AsyncRand(min, max) |
|
local pos = RotateRadius(rot_radius, rot_angle_in_frustum, lookat):SetTerrainZ() |
|
PlayFX(lightning_fx, "start", pos, pos, pos) |
|
else |
|
local pos = RotateRadius(100 * guim, AsyncRand(60 * 360), eye) |
|
PlayFX("LightningThunderAround", "start", pos) |
|
end |
|
return true |
|
end |
|
|
|
if FirstLoad then |
|
LightningThreads = false |
|
end |
|
|
|
function UpdateLightingThread(view) |
|
local lm = CurrentLightmodel[view] |
|
local lightning_thread = LightningThreads and LightningThreads[view] |
|
if not lm or not lm.lightning_enable then |
|
DeleteThread(lightning_thread) |
|
if LightningThreads then LightningThreads[view] = nil end |
|
return |
|
end |
|
if IsValidThread(lightning_thread) then |
|
return |
|
end |
|
LightningThreads = LightningThreads or {} |
|
LightningThreads[view] = CreateMapRealTimeThread(function(view) |
|
local lm = CurrentLightmodel[view] |
|
Sleep(lm and lm.lightning_delay_start or 0) |
|
while WaitLightingStrike(view) do end |
|
LightningThreads[view] = nil |
|
end, view) |
|
end |
|
|
|
function OnMsg.DoneMap() |
|
for view, thread in pairs(LightningThreads) do |
|
DeleteThread(thread) |
|
end |
|
LightningThreads = false |
|
end |
|
|
|
function OnMsg.LoadGame() |
|
for view in pairs(CurrentLightmodel) do |
|
UpdateLightingThread(view) |
|
end |
|
end |
|
|
|
function OnMsg.LightmodelChange(view, lm, time, prev_lm) |
|
local target_fx_class = "View" .. view |
|
PlayFX("SetLightmodel", "end", prev_lm and prev_lm.id or "", target_fx_class) |
|
PlayFX("SetLightmodel", "start", lm.id, target_fx_class) |
|
UpdateLightingThread(view) |
|
end |
|
|
|
function OnMsg.DoneMap() |
|
if not CurrentLightmodel then |
|
return |
|
end |
|
for view = 1, 1 do |
|
local target_fx_class = "View" .. view |
|
local lm = CurrentLightmodel[view] |
|
if lm then |
|
if lm.night then |
|
PlayFX("Day", "end", lm.id or "", target_fx_class) |
|
else |
|
PlayFX("Night", "end", lm.id or "", target_fx_class) |
|
end |
|
PlayFX("Rain", "end", lm.id or "", target_fx_class) |
|
PlayFX("Stormy", "end", lm.id or "", target_fx_class) |
|
PlayFX("SetLightmodel", "end", lm.id or "", target_fx_class) |
|
end |
|
end |
|
end |
|
|
|
function OnMsg.GedClosing(id) |
|
local app = GedConnections[id] |
|
if app.app_template == "LightmodelEditor" then |
|
hr.AutoExposureMode = EngineOptions.EyeAdaptation == "On" and 1 or 0 |
|
hr.EnablePostProcExposureSplit = 0 |
|
end |
|
end |
|
|
|
function OnMsg.GatherFXActions(list) |
|
list[#list+1] = "Day" |
|
list[#list+1] = "Night" |
|
list[#list+1] = "Rain" |
|
list[#list+1] = "SetLightmodel" |
|
end |
|
|
|
if FirstLoad then |
|
LightmodelLists = false |
|
end |
|
|
|
function UpdateLightmodelLists() |
|
local lists = {} |
|
ForEachPreset(LightmodelPreset, function(lm, group_list) |
|
if lm.use_time_of_day then |
|
local list_name = lm:GetListName() |
|
local list = lists[list_name] or {} |
|
local entry = { time = lm.time, blend_time = lm.blend_time, id = lm.id } |
|
list[#list+1] = entry |
|
lists[list_name] = list |
|
end |
|
end) |
|
for list_name, list in pairs(lists) do |
|
table.sort(list, function(lm1, lm2) return lm1.time < lm2.time end) |
|
end |
|
LightmodelLists = lists |
|
end |
|
|
|
OnMsg.BinAssetsLoaded = UpdateLightmodelLists |
|
|
|
function FindNextLightmodel(list_name, time_of_day) |
|
local list = LightmodelLists and LightmodelLists[list_name] |
|
if not list then return end |
|
assert(time_of_day >= -24*60 and time_of_day < 2*24*60) |
|
time_of_day = (time_of_day + 2*24*60) % (24*60) |
|
for i = 1, #list do |
|
local lm = list[i] |
|
if lm.time >= time_of_day then |
|
return LightmodelPresets[lm.id] |
|
end |
|
end |
|
return list[1] |
|
end |
|
|
|
function FindPrevLightmodel(list_name, time_of_day) |
|
local list = LightmodelLists and LightmodelLists[list_name] |
|
if not list then return end |
|
assert(time_of_day >= -24*60 and time_of_day < 2*24*60) |
|
time_of_day = (time_of_day + 2*24*60) % (24*60) |
|
for i = #list, 1, -1 do |
|
local lm = list[i] |
|
if lm.time <= time_of_day then |
|
return LightmodelPresets[lm.id] |
|
end |
|
end |
|
return list[#list] |
|
end |
|
|
|
|
|
|
|
function OnMsg.GedOpened(ged_id) |
|
local conn = GedConnections[ged_id] |
|
if conn and conn.app_template == "LightmodelEditor" then |
|
local root = conn:ResolveObj("root") |
|
local active_lightmodel = LightmodelPreset.GetInitialSelection() |
|
if active_lightmodel then |
|
local selection = { |
|
table.find(root, root[active_lightmodel.group]), |
|
table.find(root[active_lightmodel.group], active_lightmodel), |
|
} |
|
conn:Send("rfnApp", "SetSelection", "root", selection) |
|
end |
|
end |
|
end |
|
|
|
function LightmodelPreset.GetInitialSelection() |
|
local id, val = next(LightmodelPresets) |
|
if not id then return end |
|
return LightmodelPresets[CurrentLightmodel and CurrentLightmodel[1] and CurrentLightmodel[1].id] or val |
|
end |
|
|
|
if FirstLoad then |
|
ChangeLightmodelOverrideThread = false |
|
CelestialPoleDebugThread = false |
|
end |
|
|
|
function SetLightmodelOverrideDelay(view, lm) |
|
if ChangeLightmodelOverrideThread then |
|
DeleteThread(ChangeLightmodelOverrideThread) |
|
end |
|
ChangeLightmodelOverrideThread = CreateRealTimeThread(function() |
|
Sleep(100) |
|
SetLightmodelOverride(view, lm) |
|
ChangeLightmodelOverrideThread = false |
|
end) |
|
end |
|
|
|
function LightmodelPreset:OnEditorSelect(selection, ged) |
|
if not self:EditorCheck() then return end |
|
|
|
if IsKindOf(ged:ResolveObj("SelectedPreset"), "GedMultiSelectAdapter") then |
|
return |
|
end |
|
|
|
if selection then |
|
SetLightmodelOverrideDelay(1, self) |
|
FXCache = false |
|
else |
|
SetLightmodelOverrideDelay(1, false) |
|
end |
|
end |
|
|
|
local function AdjustColor(obj, prop, brightness) |
|
local h, s, v = UIL.RGBtoHSV(GetRGB(obj[prop])) |
|
obj[prop] = RGB(UIL.HSVtoRGB(h, s, MulDivRound(v, brightness, 100))) |
|
end |
|
|
|
local function DebugMarkPole() |
|
hr.SkyCelestialPoleDebug = 1 |
|
DeleteThread(CelestialPoleDebugThread) |
|
CelestialPoleDebugThread = CreateRealTimeThread(function() |
|
Sleep(60000) |
|
hr.SkyCelestialPoleDebug = 0 |
|
end) |
|
end |
|
|
|
function LightmodelPreset:Getcubemap_capture_preview() |
|
return table.changed(hr, "CubemapCapturePreview") and true |
|
end |
|
|
|
function LightmodelPreset:OnEditorSetProperty(prop_id, old_value, ged) |
|
if prop_id == "env_view_site" then |
|
if table.changed(hr, "ViewEnv") then |
|
self:ViewEnv() |
|
end |
|
return |
|
elseif prop_id == "sky_is" then |
|
if self[prop_id] then |
|
hr.DeferFlags = hr.DeferFlags | const.DeferFlagSkyIS |
|
else |
|
hr.DeferFlags = hr.DeferMode & ~const.DeferFlagSkyIS |
|
end |
|
return |
|
elseif prop_id == "cubemap_capture_preview" then |
|
if self[prop_id] then |
|
CubemapCaptureMode(true, "CubemapCapturePreview") |
|
else |
|
CubemapCaptureMode(false, "CubemapCapturePreview") |
|
end |
|
elseif prop_id == "env_exterior_capture_pos" or prop_id == "env_interior_capture_pos" then |
|
self.env_capture_map = GetMapName() |
|
ObjModified(self) |
|
elseif prop_id == "stars_rotation" or prop_id == "stars_pole_alt" or prop_id == "stars_pole_azi" then |
|
DelayedCall(50, DebugMarkPole) |
|
elseif prop_id == "Group" or prop_id == "use_time_of_day" or prop_id == "time" or prop_id == "blend_time" then |
|
UpdateLightmodelLists() |
|
end |
|
for feature, feature_data in pairs(LightmodelFeatureToProperties) do |
|
if prop_id == feature_data.preset_feature_prop_id then |
|
self:SetFeaturePresetId(feature, self:GetProperty(prop_id)) |
|
end |
|
end |
|
if self:EditorCheck() then |
|
DoSetLightmodel(1, self, 0) |
|
DelayedCall(300, function(object) |
|
Msg("LightmodelChange", 1, object, 0, object) |
|
end, self) |
|
end |
|
end |
|
|
|
function LightmodelPreset:Gray(root, prop, ged) |
|
local r, g, b = GetRGB( self[prop] ) |
|
local gray = (33 * r + 50 * g + 17 * b) / 100 |
|
return GedSetProperty(ged, self, prop, RGB(gray, gray, gray)) |
|
end |
|
|
|
function LightmodelPreset:ViewExteriorEnvPos() |
|
editor.ClearSelWithUndoRedo() |
|
ViewPos(self.env_exterior_capture_pos, 20*guim) |
|
end |
|
|
|
function LightmodelPreset:ViewInteriorEnvPos() |
|
editor.ClearSelWithUndoRedo() |
|
ViewPos(self.env_interior_capture_pos, 20*guim) |
|
end |
|
|
|
if FirstLoad then |
|
g_LightmodelViewEnvLastCam = false |
|
end |
|
|
|
function LightmodelPreset:ViewEnv() |
|
local envmap_name = self.id .. self.env_view_site |
|
local envmap_path = "Textures/Cubemaps/" .. envmap_name |
|
|
|
if not io.exists(envmap_path .. "Env.dds") then |
|
assert(not "Env map must be captured before viewed!") |
|
return |
|
end |
|
|
|
local envmap_sh = Presets.SHDiffuseIrradiance.Default[envmap_name] |
|
envmap_sh = envmap_sh and Decode64(envmap_sh.sh9_coefficients) |
|
|
|
DoSetLightmodel(1, LightmodelPresets.ArtPreview, 0) |
|
SetCubemap(1, envmap_path, envmap_sh, 0, 0, 0) |
|
SetCubemap(1, envmap_path, envmap_sh, 1, 0, 0) |
|
|
|
if not table.changed(hr, "ViewEnv") then |
|
table.change(hr, "ViewEnv", { |
|
DeferFlags = const.DeferFlagEnvMapOnly, |
|
RenderCodeRenderables = 0, |
|
RenderTransparent = 0, |
|
RenderParticles = 0, |
|
RenderLights = 0, |
|
EnableScreenSpaceReflections = 0, |
|
}) |
|
if not g_LightmodelViewEnvLastCam then |
|
g_LightmodelViewEnvLastCam = { GetCamera() } |
|
cameraFly.Activate(1) |
|
end |
|
end |
|
end |
|
|
|
function LightmodelPreset:HideEnv() |
|
if table.changed(hr, "ViewEnv") then |
|
table.restore(hr, "ViewEnv") |
|
DoSetLightmodel(0, self, 0) |
|
if g_LightmodelViewEnvLastCam then |
|
SetCamera(table.unpack(g_LightmodelViewEnvLastCam)) |
|
g_LightmodelViewEnvLastCam = false |
|
end |
|
end |
|
end |
|
|
|
function LightmodelPreset:UseSelectionAsExteriorEnvPos() |
|
if IsEditorActive() and #editor.GetSel() > 0 then |
|
if IsKindOf(editor.GetSel()[1], "ShaderBall") then |
|
self.env_exterior_capture_pos = editor.GetSel()[1]:GetBSphere() |
|
self.env_capture_map = GetMapName() |
|
ObjModified(self) |
|
else |
|
print("Please use a Shaderball object to mark the desired environment capture position") |
|
end |
|
end |
|
end |
|
|
|
function LightmodelPreset:UseSelectionAsInteriorEnvPos() |
|
if IsEditorActive() and #editor.GetSel() > 0 then |
|
if IsKindOf(editor.GetSel()[1], "ShaderBall") then |
|
self.env_interior_capture_pos = editor.GetSel()[1]:GetBSphere() |
|
self.env_capture_map = GetMapName() |
|
ObjModified(self) |
|
else |
|
print("Please use a Shaderball object to mark the desired environment capture position") |
|
end |
|
end |
|
end |
|
|
|
if FirstLoad then |
|
g_LMCaptureQueue = {} |
|
g_LMCaptureThread = false |
|
end |
|
|
|
function LightmodelPreset:CaptureEnvmap(site, ged) |
|
if self.env_capture_map ~= GetMapName() then |
|
if MapData[self.env_capture_map] then |
|
ChangeMap(self.env_capture_map) |
|
else |
|
assert(false, "Capture map doesn't exist") |
|
return "Capture map doesn't exist: " .. self.env_capture_map |
|
end |
|
end |
|
|
|
local env_capture_pos = site == "Interior" and self.env_interior_capture_pos or self.env_exterior_capture_pos |
|
|
|
if not env_capture_pos:IsValidZ() then |
|
return "Capture position must not be a 2D position (on the terrain)" |
|
end |
|
|
|
local map_x, map_y = terrain.GetMapSize() |
|
if env_capture_pos:x() > map_x or |
|
env_capture_pos:y() > map_y or |
|
env_capture_pos:x() < 0 or |
|
env_capture_pos:y() < 0 then |
|
assert(false, "Camera is out of map!") |
|
g_CapturingLightmodel = false |
|
return "Camera is out of map!" |
|
end |
|
|
|
local lightmodel_for_capture = LightmodelPresets[self.lm_capture] or self |
|
|
|
local sky_exp = GetSceneParam("SkyExp") |
|
local sun_int = GetSceneParam("SunIntensity") |
|
|
|
DoSetLightmodel(1, lightmodel_for_capture, 0) |
|
SetSceneParam(1, "RainEnable", 0, 0, 0) |
|
|
|
if site == "Exterior" then |
|
SetSceneParam(1, "SkyExp", lightmodel_for_capture.sky_exp + lightmodel_for_capture.env_exterior_capture_sky_exp, 0, 0) |
|
SetSceneParam(1, "SunIntensity", lightmodel_for_capture.sun_intensity + lightmodel_for_capture.env_exterior_capture_sun_int , 0, 0) |
|
else |
|
SetSceneParam(1, "SkyExp", lightmodel_for_capture.sky_exp + lightmodel_for_capture.env_interior_capture_sky_exp, 0, 0) |
|
SetSceneParam(1, "SunIntensity", lightmodel_for_capture.sun_intensity + lightmodel_for_capture.env_interior_capture_sun_int, 0, 0) |
|
end |
|
|
|
|
|
|
|
local objs_to_restore = {} |
|
MapForEach("map", g_ClassesToHideInCubemaps or "EditorVisibleObject", function(object) |
|
if object:GetEnumFlags(const.efVisible) > 0 then |
|
table.insert(objs_to_restore, object) |
|
object:ClearEnumFlags(const.efVisible) |
|
end |
|
end) |
|
WaitNextFrame(10) |
|
|
|
HDRCubemapExportAll("Textures/Cubemaps/", self.id, site, env_capture_pos) |
|
WaitNextFrame(10) |
|
|
|
for _, object in pairs(objs_to_restore) do |
|
if IsValid(object) then |
|
object:SetEnumFlags(const.efVisible) |
|
end |
|
end |
|
self:SetProperty("sky_is", false) |
|
self:SetProperty(site:lower() .. "_envmap", self.id) |
|
SetSceneParam(1, "SkyExp", sky_exp, 0, 0) |
|
SetSceneParam(1, "SunIntensity", sun_int, 0, 0) |
|
WaitNextFrame(10) |
|
ObjModified(self) |
|
DoSetLightmodel(1, self, 0) |
|
|
|
if ged then |
|
local result = ged:Send("rfnApp", "ReloadImage", ConvertToOSPath("Textures/Cubemaps/Thumbnails/" .. self.id .. site .. ".jpg")) |
|
assert(not result) |
|
end |
|
end |
|
|
|
function LMCaptureThread() |
|
while g_LMCaptureQueue[1] do |
|
local lm, site, ged = table.unpack(g_LMCaptureQueue[1]) |
|
table.remove(g_LMCaptureQueue, 1) |
|
lm:CaptureEnvmap(site, ged) |
|
print(lm.id) |
|
end |
|
g_LMCaptureThread = false |
|
end |
|
|
|
function AddLMCapture(lm, site, ged) |
|
table.insert(g_LMCaptureQueue, {lm, site, ged}) |
|
if not g_LMCaptureThread then |
|
g_LMCaptureThread = CreateRealTimeThread( LMCaptureThread ) |
|
end |
|
end |
|
|
|
function LightmodelPreset:CaptureExteriorEnvmap(root, prop_id, ged) |
|
if not self:EditorCheck(true) then return end |
|
AddLMCapture(self, "Exterior", ged) |
|
end |
|
|
|
function LightmodelPreset:CaptureInteriorEnvmap(root, prop_id, ged) |
|
if not self:EditorCheck(true) then return end |
|
AddLMCapture(self, "Interior", ged) |
|
end |
|
|
|
function LightmodelPreset:CaptureBothEnvmaps(root, prop_id, ged) |
|
if not self:EditorCheck(true) then return end |
|
AddLMCapture(self, "Exterior", ged) |
|
AddLMCapture(self, "Interior", ged) |
|
end |
|
|
|
function LightmodelPreset:ConvertHDRPano(site, ged) |
|
if not self:EditorCheck(true) or self.hdr_pano == "" then |
|
return |
|
end |
|
local _, base_name, _ = SplitPath(pano_path) |
|
HDRCubemapFromPano("Textures/Cubemaps/", base_name, site, self.hdr_pano) |
|
if ged then |
|
local result = ged:Send("rfnApp", "ReloadImage", ConvertToOSPath("Textures/Cubemaps/Thumbnails/" .. base_name .. site .. ".jpg")) |
|
assert(not result) |
|
end |
|
end |
|
|
|
function LightmodelPreset:ConvertExteriorEnvmap(root, prop_id, ged) |
|
self:ConvertHDRPano("Exterior", ged) |
|
end |
|
|
|
function LightmodelPreset:ConvertInteriorEnvmap(root, prop_id, ged) |
|
self:ConvertHDRPano("Interior", ged) |
|
end |
|
|
|
function LightmodelPreset:EditorCheck(print_err) |
|
if CurrentMap == "" then |
|
if print_err then |
|
print("Load a map to access this Lightmodel action.") |
|
end |
|
return false |
|
end |
|
return true |
|
end |
|
|
|
function LightmodelPreset:GetCubemapWarning() |
|
if not MapData[self.env_capture_map] then |
|
return string.format("Map for capturing cubemaps doesn't exist: %s", self.env_capture_map) |
|
end |
|
end |
|
|
|
function LightmodelPreset:GetWarning() |
|
local cubemap_warning = self:GetCubemapWarning() |
|
if cubemap_warning then |
|
return cubemap_warning |
|
end |
|
end |
|
|
|
function LightmodelPreset:AutoExposureOn() |
|
hr.AutoExposureMode = 1 |
|
hr.EnablePostProcExposureSplit = 0 |
|
end |
|
|
|
function LightmodelPreset:AutoExposureOff() |
|
hr.AutoExposureMode = 0 |
|
hr.EnablePostProcExposureSplit = 0 |
|
end |
|
|
|
function LightmodelPreset:AutoExposureSplit() |
|
hr.EnablePostProcExposureSplit = 1 |
|
end |
|
|
|
function LightmodelPreset:AutoExposureDebugToggle() |
|
ToggleHR "AutoExposureDebug" |
|
end |
|
|
|
function LightmodelEditorTakeScreenshots(ged, obj) |
|
local lightmodels = obj:IsKindOf("GedMultiSelectAdapter") and obj.__objects or { obj } |
|
local prefix = os.date("%Y%m%d_%H%M%S_", os.time()) |
|
local items = {} |
|
AsyncCreatePath("AppData/LightmodelScreenshots") |
|
for i, lm in ipairs(lightmodels) do |
|
DoSetLightmodel(1, lm, 0) |
|
WaitNextFrame(3) |
|
LockCamera("Screenshot") |
|
local filename = string.format("AppData/LightmodelScreenshots/%s_%s.png", prefix, lm.id) |
|
MovieWriteScreenshot(filename, 0, 16, false) |
|
items[#items+1] = ScreenshotItem:new{ display_name = lm.id, file_path = filename } |
|
UnlockCamera("Screenshot") |
|
WaitNextFrame(1) |
|
end |
|
local sdv = OpenGedApp("ScreenshotDiffViewer", items) |
|
for _, s in ipairs(items) do |
|
sdv:Send("rfnApp", "rfnSetSelectedFilePath", s.file_path, true) |
|
end |
|
end |