diff --git a/code/def_files/data/effects/fog-f.sdr b/code/def_files/data/effects/fog-f.sdr index ca14335dea8..3785d719722 100644 --- a/code/def_files/data/effects/fog-f.sdr +++ b/code/def_files/data/effects/fog-f.sdr @@ -15,6 +15,9 @@ layout (std140) uniform genericData { float fog_density; float zNear; float zFar; + + float clip_inf_dist; + float clip_dist; }; void main() @@ -28,6 +31,9 @@ void main() // Now we compute the depth value in projection space using the clipping plane information float view_depth = 2.0 * zNear * zFar / (zFar + zNear - depth_normalized * (zFar - zNear)); + float skybox_compat_fake = step(1.0, depth_val); + view_depth = clamp(view_depth, 0.0, mix(clip_dist, clip_inf_dist, skybox_compat_fake)); + if (isinf(view_depth)) { fragOut0.rgb = color_in.rgb; } else { diff --git a/code/graphics/material.cpp b/code/graphics/material.cpp index b79e690750a..223affd5456 100644 --- a/code/graphics/material.cpp +++ b/code/graphics/material.cpp @@ -674,14 +674,12 @@ bool model_material::is_batched() const return Batched; } -void model_material::set_fog(int r, int g, int b, float _near, float _far) +void model_material::set_fog(int r, int g, int b) { Fog_params.enabled = true; Fog_params.r = r; Fog_params.g = g; Fog_params.b = b; - Fog_params.dist_near = _near; - Fog_params.dist_far = _far; } void model_material::set_fog() diff --git a/code/graphics/material.h b/code/graphics/material.h index 78d8b88f067..64ad751a62f 100644 --- a/code/graphics/material.h +++ b/code/graphics/material.h @@ -172,8 +172,6 @@ class model_material : public material int r = 0; int g = 0; int b = 0; - float dist_near = -1.0f; - float dist_far = -1.0f; }; private: @@ -255,7 +253,7 @@ class model_material : public material int get_shader_runtime_early_flags() const; int get_shader_runtime_flags() const; - void set_fog(int r, int g, int b, float near, float far); + void set_fog(int r, int g, int b); void set_fog(); bool is_fogged() const; const fog& get_fog() const; diff --git a/code/graphics/opengl/gropengldeferred.cpp b/code/graphics/opengl/gropengldeferred.cpp index b3acf8faf84..bcb7772ac48 100644 --- a/code/graphics/opengl/gropengldeferred.cpp +++ b/code/graphics/opengl/gropengldeferred.cpp @@ -540,8 +540,8 @@ void gr_opengl_deferred_lighting_finish() GL_state.Texture.Enable(0, GL_TEXTURE_2D, Scene_composite_texture); GL_state.Texture.Enable(1, GL_TEXTURE_2D, Scene_depth_texture); - float fog_near, fog_far, fog_density; - neb2_get_adjusted_fog_values(&fog_near, &fog_far, &fog_density); + float fog_near, fog_density; + neb2_get_adjusted_fog_values(&fog_near, &fog_density); unsigned char r, g, b; neb2_get_fog_color(&r, &g, &b); @@ -556,6 +556,8 @@ void gr_opengl_deferred_lighting_finish() data->fog_color.xyz.z = b / 255.f; data->zNear = Min_draw_distance; data->zFar = Max_draw_distance; + data->clip_inf_dist = Neb2_fog_skybox_clip_distance; + data->clip_dist = Neb2_fog_clip_distance; }); opengl_draw_full_screen_textured(0.0f, 0.0f, 1.0f, 1.0f); diff --git a/code/graphics/uniforms.cpp b/code/graphics/uniforms.cpp index a112e69fc66..2be9c3b7c6c 100644 --- a/code/graphics/uniforms.cpp +++ b/code/graphics/uniforms.cpp @@ -218,8 +218,6 @@ void convert_model_material(model_uniform_data* data_out, auto& fog_params = material.get_fog(); if (fog_params.enabled) { - data_out->fogStart = fog_params.dist_near; - data_out->fogScale = 1.0f / (fog_params.dist_far - fog_params.dist_near); data_out->fogColor.xyzw.x = i2fl(fog_params.r) / 255.0f; data_out->fogColor.xyzw.y = i2fl(fog_params.g) / 255.0f; data_out->fogColor.xyzw.z = i2fl(fog_params.b) / 255.0f; diff --git a/code/graphics/util/uniform_structs.h b/code/graphics/util/uniform_structs.h index 391e6d36fa5..5fc0f0de06c 100644 --- a/code/graphics/util/uniform_structs.h +++ b/code/graphics/util/uniform_structs.h @@ -87,8 +87,7 @@ struct model_uniform_data { model_light lights[MAX_UNIFORM_LIGHTS]; float outlineWidth; - float fogStart; - float fogScale; + float tempPad[2]; int buffer_matrix_offset; vec4 clip_equation; @@ -288,8 +287,10 @@ struct fog_data { float fog_density; float zNear; float zFar; + float clip_inf_dist; + float clip_dist; - float pad[1]; + float pad[3]; }; struct volumetric_fog_data { diff --git a/code/mission/missionparse.cpp b/code/mission/missionparse.cpp index 86fa64407bd..f01722e47e8 100644 --- a/code/mission/missionparse.cpp +++ b/code/mission/missionparse.cpp @@ -820,11 +820,34 @@ void parse_mission_info(mission *pm, bool basic = false) if (!basic) nebl_set_storm(Mission_parse_storm_name); } - if(optional_string("+Fog Near Mult:")){ - stuff_float(&Neb2_fog_near_mult); - } - if(optional_string("+Fog Far Mult:")){ - stuff_float(&Neb2_fog_far_mult); + + { + float near_mult = 1.f, far_mult = 1.f; + //Pre-26.0 missions always need legacy conversion unless the modern values are found (once they are actually stored) + bool legacy_fog = gameversion::version(26, 0, 0) > pm->required_fso_version; + if(optional_string("+Fog Near Mult:")){ + stuff_float(&near_mult); + extern float Neb2_fog_near_mult; + Neb2_fog_near_mult = near_mult; + legacy_fog = true; + } + if(optional_string("+Fog Far Mult:")){ + stuff_float(&far_mult); + extern float Neb2_fog_far_mult; + Neb2_fog_far_mult = far_mult; + legacy_fog = true; + } + + if (legacy_fog) { + //This stems from the weird unchangeable constants of legacy fog + Neb2_fog_1000m_visibility = powf(10.f, -100.f / (75.f * far_mult - near_mult)); + Neb2_fog_near_distance = 10.f * near_mult; + Neb2_fog_skybox_clip_distance = 0.f; // Apparently, skybox fog was just outright broken... + Neb2_fog_clip_distance = Default_max_draw_distance; + } + else { + //To be added once the corresponding FRED dialogue is updated + } } // Goober5000 - ship contrail speed threshold diff --git a/code/missioneditor/missionsave.cpp b/code/missioneditor/missionsave.cpp index d78410b029d..672d9363fa3 100644 --- a/code/missioneditor/missionsave.cpp +++ b/code/missioneditor/missionsave.cpp @@ -2525,6 +2525,9 @@ int Fred_mission_save::save_mission_info() // Goober5000 if (save_config.save_format != MissionFormat::RETAIL) { // write out the nebula clipping multipliers + //TODO write modernized values + extern float Neb2_fog_near_mult; + extern float Neb2_fog_far_mult; fout("\n+Fog Near Mult: %f\n", Neb2_fog_near_mult); fout("\n+Fog Far Mult: %f\n", Neb2_fog_far_mult); diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index bfad90a4d1f..97ba512945f 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -1527,7 +1527,6 @@ void submodel_render_queue(const model_render_params *render_info, model_draw_li } uint64_t flags = render_info->get_model_flags(); - int objnum = render_info->get_object_number(); // Set the flags we will pass to the tmapper uint tmap_flags = TMAP_FLAG_GOURAUD | TMAP_FLAG_RGB; @@ -1591,17 +1590,10 @@ void submodel_render_queue(const model_render_params *render_info, model_draw_li // RT - Put this here to fog debris if( tmap_flags & TMAP_FLAG_PIXEL_FOG ) { - float fog_near, fog_far; - object *obj = NULL; - - if (objnum >= 0) - obj = &Objects[objnum]; - - neb2_get_adjusted_fog_values(&fog_near, &fog_far, nullptr, obj); unsigned char r, g, b; neb2_get_fog_color(&r, &g, &b); - rendering_material.set_fog(r, g, b, fog_near, fog_far); + rendering_material.set_fog(r, g, b); } else { rendering_material.set_fog(); } @@ -2817,13 +2809,10 @@ void model_render_queue(const model_render_params* interp, model_draw_list* scen // if we're in nebula mode, fog everything except for the warp holes and other non-fogged models if ( (The_mission.flags[Mission::Mission_Flags::Fullneb]) && (Neb2_render_mode != NEB2_RENDER_NONE) && !(model_flags & MR_NO_FOGGING) ) { - float fog_near = 10.0f, fog_far = 1000.0f; - neb2_get_adjusted_fog_values(&fog_near, &fog_far, nullptr, objp); - unsigned char r, g, b; neb2_get_fog_color(&r, &g, &b); - rendering_material.set_fog(r, g, b, fog_near, fog_far); + rendering_material.set_fog(r, g, b); } else { rendering_material.set_fog(); } diff --git a/code/nebula/neb.cpp b/code/nebula/neb.cpp index 7f6cb4048d5..d4828cb0d00 100644 --- a/code/nebula/neb.cpp +++ b/code/nebula/neb.cpp @@ -79,18 +79,6 @@ char Neb2_texture_name[MAX_FILENAME_LEN] = ""; float max_rotation = 3.75f; float neb2_flash_fade = 0.3f; -//WMC - these were originally indexed to SHIP_TYPE_FIGHTER_BOMBER -const static float Default_fog_near = 10.0f; -const static float Default_fog_far = 750.0f; - -// fog near and far values for rendering the background nebula -#define NEB_BACKG_FOG_NEAR_GLIDE 2.5f -#define NEB_BACKG_FOG_NEAR_D3D 4.5f -#define NEB_BACKG_FOG_FAR_GLIDE 10.0f -#define NEB_BACKG_FOG_FAR_D3D 10.0f -float Neb_backg_fog_near = NEB_BACKG_FOG_NEAR_GLIDE; -float Neb_backg_fog_far = NEB_BACKG_FOG_FAR_GLIDE; - // stats int pneb_tried = 0; // total pnebs tried to render int pneb_tossed_alpha = 0; // pnebs tossed because of alpha optimization @@ -104,12 +92,15 @@ int neb_tossed_count = 0; // nebs tossed because of max render count // the AWACS suppression level for the nebula float Neb2_awacs = -1.0f; -// The visual render distance multipliers for the nebula +//Deprecated! Only here very temporary until the new values are stored correctly float Neb2_fog_near_mult = 1.0f; float Neb2_fog_far_mult = 1.0f; -// this is the percent of visibility at the fog far distance -const float NEB_FOG_FAR_PCT = 0.1f; +// The visual render distance multipliers for the nebula +float Neb2_fog_near_distance = 10.0f; +float Neb2_fog_1000m_visibility = 0.00464158883f; +float Neb2_fog_skybox_clip_distance = Default_max_draw_distance; +float Neb2_fog_clip_distance = Default_max_draw_distance; float Neb2_fog_visibility_trail = 1.0f; float Neb2_fog_visibility_thruster = 1.5f; @@ -397,8 +388,10 @@ void neb2_get_fog_color(ubyte *r, ubyte *g, ubyte *b) void neb2_pre_level_init() { Neb2_awacs = -1.0f; - Neb2_fog_near_mult = 1.0f; - Neb2_fog_far_mult = 1.0f; + Neb2_fog_near_distance = 10.0f; + Neb2_fog_1000m_visibility = 0.00464158883f; + Neb2_fog_skybox_clip_distance = Max_draw_distance; + Neb2_fog_clip_distance = Max_draw_distance; strcpy_s(Neb2_texture_name, ""); clear_all_bits(Neb2_poof_flags.get(), Poof_info.size()); @@ -531,10 +524,6 @@ void neb2_post_level_init(bool fog_color_override) neb_tossed_dot = 0; neb_tossed_count = 0; - // setup proper fogging values - Neb_backg_fog_near = NEB_BACKG_FOG_NEAR_D3D; - Neb_backg_fog_far = NEB_BACKG_FOG_FAR_D3D; - // if we are going to use fullneb, but aren't fullneb yet, then be sure to reset our mode if ( !(The_mission.flags[Mission::Mission_Flags::Fullneb]) ) { Neb2_render_mode = NEB2_RENDER_NONE; @@ -542,8 +531,7 @@ void neb2_post_level_init(bool fog_color_override) } // set the mission fog near dist and density - float fog_far; - neb2_get_adjusted_fog_values(&nNf_near, &fog_far, &nNf_density, nullptr); + neb2_get_adjusted_fog_values(&nNf_near, &nNf_density); for (float& accum : Poof_accum) accum = 0.0f; @@ -649,7 +637,7 @@ DCF(neb_skip, "Toggles culling of objects obscured by nebula") } int neb2_skip_render(object *objp, float z_depth) { - float fog_near, fog_far, fog_density; + float fog_near, fog_density; // if we're never skipping if (!neb_skip_opt) { @@ -657,7 +645,7 @@ int neb2_skip_render(object *objp, float z_depth) } // get near and far fog values based upon object type and rendering mode - neb2_get_adjusted_fog_values(&fog_near, &fog_far, &fog_density); + neb2_get_adjusted_fog_values(&fog_near, &fog_density); float fog = pow(fog_density, z_depth - fog_near + objp->radius); // by object type @@ -1071,71 +1059,15 @@ void neb2_render_poofs() #endif } -/* -//Object types -#define OBJ_NONE 0 //unused object -#define OBJ_SHIP 1 //a ship -#define OBJ_WEAPON 2 //a laser, missile, etc -#define OBJ_FIREBALL 3 //an explosion -#define OBJ_START 4 //a starting point marker (player start, etc) -#define OBJ_WAYPOINT 5 //a waypoint object, maybe only ever used by Fred -#define OBJ_DEBRIS 6 //a flying piece of ship debris -#define OBJ_CMEASURE 7 //a countermeasure, such as chaff -#define OBJ_GHOST 8 //so far, just a placeholder for when a player dies. -#define OBJ_POINT 9 //generic object type to display a point in Fred. -#define OBJ_SHOCKWAVE 10 // a shockwave -#define OBJ_WING 11 // not really a type used anywhere, but I need it for Fred. -#define OBJ_OBSERVER 12 // used for multiplayer observers (possibly single player later) -#define OBJ_ASTEROID 13 // An asteroid, you know, a big rock, like debris, sort of. -#define OBJ_JUMP_NODE 14 // A jump node object, used only in Fred. -#define OBJ_BEAM 15 // beam weapons. we have to roll them into the object system to get the benefits of the collision pairs -*/ -// get near and far fog values based upon object type and rendering mode -void neb2_get_fog_values(float *fnear, float *ffar, object *objp) -{ - int type_index = -1; - - //use defaults - *fnear = Default_fog_near; - *ffar = Default_fog_far; - - if (objp == NULL) { - return; - } - - // Future TODO: Add fog_start_dist and fog_complete_dist to Props - // determine what fog index to use - if(objp->type == OBJ_SHIP) { - Assert((objp->instance >= 0) && (objp->instance < MAX_SHIPS)); - if((objp->instance >= 0) && (objp->instance < MAX_SHIPS)) { - type_index = ship_query_general_type(objp->instance); - if(type_index > 0) { - *fnear = Ship_types[type_index].fog_start_dist; - *ffar = Ship_types[type_index].fog_complete_dist; - } - } - } else if (objp->type == OBJ_FIREBALL) { //mostly here for the warp effect - *fnear = objp->radius*2; - *ffar = (objp->radius*objp->radius*200)+objp->radius*200; - return; - } -} - // This version of the function allows for global adjustment to fog values -void neb2_get_adjusted_fog_values(float *fnear, float *ffar, float *fdensity, object *objp) +void neb2_get_adjusted_fog_values(float *fnear, float *fdensity) { - neb2_get_fog_values(fnear, ffar, objp); - - // Multiply fog distances by mission multipliers - *fnear *= Neb2_fog_near_mult; - *ffar *= Neb2_fog_far_mult; + // There was code here that adjusted distanced based on object type, but at the time of reworking this, the code was effectively dead and never used. - // Avoide divide-by-zero - if ((*fnear - *ffar) == 0) - *ffar = *fnear + 1.0f; + *fnear = Neb2_fog_near_distance; if (fdensity != nullptr) - *fdensity = powf(NEB_FOG_FAR_PCT, 1 / (*ffar - *fnear)); + *fdensity = powf(Neb2_fog_1000m_visibility, 1.f / 1000.f); } // given a position, returns 0 - 1 the fog visibility of that position, 0 = completely obscured diff --git a/code/nebula/neb.h b/code/nebula/neb.h index aa6a33e93f8..b300f77100e 100644 --- a/code/nebula/neb.h +++ b/code/nebula/neb.h @@ -39,8 +39,10 @@ extern int Neb2_render_mode; extern float Neb2_awacs; // The visual render distance multipliers for the nebula -extern float Neb2_fog_near_mult; -extern float Neb2_fog_far_mult; +extern float Neb2_fog_near_distance; +extern float Neb2_fog_1000m_visibility; +extern float Neb2_fog_skybox_clip_distance; +extern float Neb2_fog_clip_distance; extern float Neb2_fog_visibility_trail; extern float Neb2_fog_visibility_thruster; @@ -170,11 +172,8 @@ void neb2_fade_poof(int poof_idx, int time, bool type); // render the player nebula void neb2_render_poofs(); -// get near and far fog values based upon object type and rendering mode -void neb2_get_fog_values(float *fnear, float *ffar, object *obj = NULL); - // get adjusted near and far fog values (allows mission-specific fog adjustments) -void neb2_get_adjusted_fog_values(float *fnear, float *ffar, float *fdensity = nullptr, object *obj = nullptr); +void neb2_get_adjusted_fog_values(float *fnear, float *fdensity = nullptr); // given a position, returns 0 - 1 the fog visibility of that position, 0 = completely obscured // distance_mult will multiply the result, use for things that can be obscured but can 'shine through' the nebula more than normal diff --git a/code/object/objectsort.cpp b/code/object/objectsort.cpp index 29281e1e1bb..fde3af712a5 100644 --- a/code/object/objectsort.cpp +++ b/code/object/objectsort.cpp @@ -208,7 +208,6 @@ void obj_render_all(const std::function& render_function, bool *d { object *objp; int i; - float fog_near, fog_far, fog_density; objp = Objects; @@ -274,9 +273,6 @@ void obj_render_all(const std::function& render_function, bool *d // if we're fullneb, fire up the fog - this also generates a fog table if (full_neb) { - // get the fog values - neb2_get_adjusted_fog_values(&fog_near, &fog_far, &fog_density, obj); - // maybe skip rendering an object because its obscured by the nebula if(neb2_skip_render(obj, os->z)){ continue; diff --git a/code/scripting/api/libs/mission.cpp b/code/scripting/api/libs/mission.cpp index 395c254fda6..8f604249af4 100644 --- a/code/scripting/api/libs/mission.cpp +++ b/code/scripting/api/libs/mission.cpp @@ -2295,24 +2295,63 @@ ADE_VIRTVAR(NebulaSensorRange, l_Mission, "number", "Gets or sets the Neb2_awacs return ade_set_args(L, "f", Neb2_awacs); } -ADE_VIRTVAR(NebulaNearMult, l_Mission, "number", "Gets or sets the multiplier of the near plane of the current nebula.", "number", "The multiplier of the near plane.") +ADE_VIRTVAR_DEPRECATED(NebulaNearMult, l_Mission, "number", "Gets or sets the multiplier of the near plane of the current nebula.", "number", "The multiplier of the near plane.", gameversion::version(26, 0), "Deprecated in favor of NebulaNearDistance.") { float fog_near = 0.0f; if (ADE_SETTING_VAR && ade_get_args(L, "*f", &fog_near)) - Neb2_fog_near_mult = fog_near; + Neb2_fog_near_distance = fog_near * 10.f; - return ade_set_args(L, "f", Neb2_fog_near_mult); + return ade_set_args(L, "f", Neb2_fog_near_distance / 10.f); } -ADE_VIRTVAR(NebulaFarMult, l_Mission, "number", "Gets or sets the multiplier of the far plane of the current nebula.", "number", "The multiplier of the far plane.") +ADE_VIRTVAR_DEPRECATED(NebulaFarMult, l_Mission, "number", "Gets or sets the multiplier of the far plane of the current nebula.", "number", "The multiplier of the far plane.", gameversion::version(26, 0), "Deprecated. Had no effect.") { float fog_far = 0.0f; - if (ADE_SETTING_VAR && ade_get_args(L, "*f", &fog_far)) - Neb2_fog_far_mult = fog_far; + if (ADE_SETTING_VAR && ade_get_args(L, "*f", &fog_far)) {} - return ade_set_args(L, "f", Neb2_fog_far_mult); + return ade_set_args(L, "f", 1.f); +} + +ADE_VIRTVAR(NebulaNearDistance, l_Mission, "number", "Gets or sets the distance of the near plane of the current nebula.", "number", "The distance of the near plane.") +{ + float fog_near = 0.0f; + + if (ADE_SETTING_VAR && ade_get_args(L, "*f", &fog_near)) + Neb2_fog_near_distance = fog_near; + + return ade_set_args(L, "f", Neb2_fog_near_distance); +} + +ADE_VIRTVAR(NebulaClipDistance, l_Mission, "number", "Gets or sets the distance after which the nebula does not get thicker.", "number", "The clip distance of the nebula.") +{ + float fog_clip = 0.0f; + + if (ADE_SETTING_VAR && ade_get_args(L, "*f", &fog_clip)) + Neb2_fog_clip_distance = fog_clip; + + return ade_set_args(L, "f", Neb2_fog_clip_distance); +} + +ADE_VIRTVAR(NebulaSkyboxClipDistance, l_Mission, "number", "Gets or sets the distance of the skybox to the camera for the purposes of fogging.", "number", "The clip distance of the nebula for skyboxes.") +{ + float fog_clip = 0.0f; + + if (ADE_SETTING_VAR && ade_get_args(L, "*f", &fog_clip)) + Neb2_fog_skybox_clip_distance = fog_clip; + + return ade_set_args(L, "f", Neb2_fog_skybox_clip_distance); +} + +ADE_VIRTVAR(NebulaTransparency, l_Mission, "number", "Gets or sets the transparency of the nebula at 1000m nebula depth. 0 is fully opaque, 1 is fully transparent.", "number", "The nebula transparency.") +{ + float fog_transparency = 0.0f; + + if (ADE_SETTING_VAR && ade_get_args(L, "*f", &fog_transparency)) + Neb2_fog_1000m_visibility = fog_transparency; + + return ade_set_args(L, "f", Neb2_fog_1000m_visibility); } ADE_FUNC(isSubspace, l_Mission, nullptr, "Get whether or not the current mission being played is set in subspace", "boolean", "true if in subspace, false if not")