diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 4d41d2e94afb..5b41ed6db94f 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -783,6 +783,7 @@
Line width of the curve path geometry, visible when "Visible Paths" is enabled in the Debug menu.
+ [b]Note:[/b] This setting is only effective in 2D. For 3D, set [member rendering/driver/line_drawing/width] instead.
Sets the driver to be used by the display server. This property can not be edited directly, instead, set the driver using the platform-specific overrides.
@@ -2434,6 +2435,12 @@
If [code]true[/code], performs a previous depth pass before rendering 3D materials. This increases performance significantly in scenes with high overdraw, when complex materials and lighting are used. However, in scenes with few occluded surfaces, the depth prepass may reduce performance. If your game is viewed from a fixed angle that makes it easy to avoid overdraw (such as top-down or side-scrolling perspective), consider disabling the depth prepass to improve performance. This setting can be changed at run-time to optimize performance depending on the scene currently being viewed.
[b]Note:[/b] Depth prepass is only supported when using the Forward+ or Compatibility rendering method. When using the Mobile rendering method, there is no depth prepass performed.
+
+ Render hardware-based 3D lines using the specified value as a thickness (in pixels). Wire thickness does not depend on distance from the camera. This setting affects all lines drawn in 3D, including gizmos in the editor and debug draw options. This can be used to make debug drawing more visible, particularly when using a high-resolution viewport or on hiDPI displays.
+ [b]Note:[/b] This setting is only implemented in the Forward+ and Mobile rendering methods. In Compatibility, line drawing is always 1 pixel thick.
+ [b]Note:[/b] This setting relies on hardware capabilities for drawing lines thicker than 1 pixel. Support on Windows and Linux is generally good. Line widths greater than 1 pixel are rarely supported on Android. macOS and iOS do not support line widths greater than 1 pixel.
+ [b]Note:[/b] This setting has no effect on 2D rendering. For Path2D debug drawing, you can adjust [member debug/shapes/paths/geometry_width] instead.
+
The thread model to use for rendering. Rendering on a thread may improve performance, but synchronizing to the main thread can cause a bit more jitter.
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 76d8972ad98d..98f1d11c30d8 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -457,6 +457,7 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
pipeline_key.framebuffer_format_id = framebuffer_format;
pipeline_key.wireframe = p_params->force_wireframe;
+ pipeline_key.line_width = line_width;
pipeline_key.ubershader = 0;
const RD::PolygonCullMode cull_mode = shader->get_cull_mode_from_cull_variant(cull_variant);
@@ -4341,6 +4342,7 @@ void RenderForwardClustered::_mesh_compile_pipelines_for_surface(const SurfacePi
pipeline_key.cull_mode = RD::POLYGON_CULL_DISABLED;
pipeline_key.primitive_type = mesh_storage->mesh_surface_get_primitive(p_surface.mesh_surface);
pipeline_key.wireframe = false;
+ pipeline_key.line_width = 1;
// Grab the shader and surface used for most passes.
const uint32_t multiview_iterations = multiview_enabled ? 2 : 1;
@@ -4735,6 +4737,8 @@ void RenderForwardClustered::_update_shader_quality_settings() {
RenderForwardClustered::RenderForwardClustered() {
singleton = this;
+ line_width = float(GLOBAL_GET("rendering/driver/line_drawing/width"));
+
/* SCENE SHADER */
{
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index ebc291e8031a..25d5626ce466 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -160,6 +160,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID render_base_uniform_set;
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
+ float line_width = 1.0f;
void _update_render_base_uniform_set();
RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture, const RendererRD::MaterialStorage::Samplers &p_samplers);
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 532b5b6484e0..594d24af41fc 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -280,7 +280,8 @@ void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pip
"VERSION:", p_pipeline_key.version,
"PASS FLAGS:", p_pipeline_key.color_pass_flags,
"SPEC PACKED #0:", p_pipeline_key.shader_specialization.packed_0,
- "WIREFRAME:", p_pipeline_key.wireframe);
+ "WIREFRAME:", p_pipeline_key.wireframe,
+ "LINE WIDTH:", p_pipeline_key.line_width);
#endif
// Color pass -> attachment 0: Color/Diffuse, attachment 1: Separate Specular, attachment 2: Motion Vectors
@@ -298,7 +299,6 @@ void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pip
depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
}
- bool depth_pre_pass_enabled = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
RD::RenderPrimitive primitive_rd_table[RS::PRIMITIVE_MAX] = {
RD::RENDER_PRIMITIVE_POINTS,
@@ -313,6 +313,7 @@ void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pip
RD::PipelineRasterizationState raster_state;
raster_state.cull_mode = p_pipeline_key.cull_mode;
raster_state.wireframe = wireframe || p_pipeline_key.wireframe;
+ raster_state.line_width = p_pipeline_key.line_width;
RD::PipelineMultisampleState multisample_state;
multisample_state.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_pipeline_key.framebuffer_format_id, 0);
@@ -335,6 +336,7 @@ void SceneShaderForwardClustered::ShaderData::_create_pipeline(PipelineKey p_pip
} else {
blend_state = blend_state_color_opaque;
+ const bool depth_pre_pass_enabled = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
if (depth_pre_pass_enabled) {
// We already have a depth from the depth pre-pass, there is no need to write it again.
// In addition we can use COMPARE_OP_EQUAL instead of COMPARE_OP_LESS_OR_EQUAL.
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
index 136514588ac2..4b8e5cc2f704 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h
@@ -172,6 +172,7 @@ class SceneShaderForwardClustered {
uint32_t color_pass_flags = 0;
ShaderSpecialization shader_specialization = {};
uint32_t wireframe = false;
+ float line_width = 1.0f;
uint32_t ubershader = false;
uint32_t hash() const {
@@ -185,6 +186,7 @@ class SceneShaderForwardClustered {
h = hash_murmur3_one_32(shader_specialization.packed_1, h);
h = hash_murmur3_one_32(shader_specialization.packed_2, h);
h = hash_murmur3_one_32(wireframe, h);
+ h = hash_murmur3_one_32(line_width, h);
h = hash_murmur3_one_32(ubershader, h);
return hash_fmix32(h);
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 978ce097d34a..df9e457a6cf6 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -2240,6 +2240,7 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
pipeline_key.framebuffer_format_id = framebuffer_format;
pipeline_key.wireframe = p_params->force_wireframe;
+ pipeline_key.line_width = line_width;
pipeline_key.render_pass = p_params->subpass;
pipeline_key.ubershader = 0;
@@ -3148,6 +3149,8 @@ void RenderForwardMobile::_update_shader_quality_settings() {
RenderForwardMobile::RenderForwardMobile() {
singleton = this;
+ line_width = float(GLOBAL_GET("rendering/driver/line_drawing/width"));
+
sky.set_texture_format(_render_buffers_get_color_format());
String defines;
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index 96f535ef459b..e49723988700 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -165,6 +165,7 @@ class RenderForwardMobile : public RendererSceneRenderRD {
void _pre_opaque_render(RenderDataRD *p_render_data);
uint64_t lightmap_texture_array_version = 0xFFFFFFFF;
+ float line_width = 1.0f;
void _update_render_base_uniform_set();
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index 6dcaadddd3ff..174382282198 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -238,7 +238,8 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli
"SPEC PACKED #0:", p_pipeline_key.shader_specialization.packed_0,
"SPEC PACKED #1:", p_pipeline_key.shader_specialization.packed_1,
"RENDER PASS:", p_pipeline_key.render_pass,
- "WIREFRAME:", p_pipeline_key.wireframe);
+ "WIREFRAME:", p_pipeline_key.wireframe,
+ "LINE WIDTH:", p_pipeline_key.line_width);
#endif
RD::PipelineColorBlendState::Attachment blend_attachment = blend_mode_to_blend_attachment(BlendMode(blend_mode));
@@ -272,6 +273,7 @@ void SceneShaderForwardMobile::ShaderData::_create_pipeline(PipelineKey p_pipeli
RD::PipelineRasterizationState raster_state;
raster_state.cull_mode = p_pipeline_key.cull_mode;
raster_state.wireframe = wireframe || p_pipeline_key.wireframe;
+ raster_state.line_width = p_pipeline_key.line_width;
RD::PipelineMultisampleState multisample_state;
multisample_state.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_pipeline_key.framebuffer_format_id, 0);
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index c1095d29dc51..392d060bca6a 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -143,6 +143,7 @@ class SceneShaderForwardMobile {
ShaderVersion version = SHADER_VERSION_MAX;
uint32_t render_pass = 0;
uint32_t wireframe = false;
+ float line_width = 1.0f;
uint32_t ubershader = false;
uint32_t hash() const {
@@ -156,6 +157,7 @@ class SceneShaderForwardMobile {
h = hash_murmur3_one_32(version, h);
h = hash_murmur3_one_32(render_pass, h);
h = hash_murmur3_one_32(wireframe, h);
+ h = hash_murmur3_one_32(line_width, h);
h = hash_murmur3_one_32(ubershader, h);
return hash_fmix32(h);
}
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 53dda24dc3e3..80ebb7312ae5 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -3599,6 +3599,7 @@ void RenderingServer::init() {
GLOBAL_DEF_RST("rendering/driver/depth_prepass/enable", true);
GLOBAL_DEF_RST("rendering/driver/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple");
+ GLOBAL_DEF_RST(PropertyInfo(Variant::FLOAT, "rendering/driver/line_drawing/width", PROPERTY_HINT_RANGE, "1.0,8.0,0.001"), 1.0);
GLOBAL_DEF_RST("rendering/textures/default_filters/use_nearest_mipmap_filter", false);
GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/textures/default_filters/anisotropic_filtering_level", PROPERTY_HINT_ENUM, String::utf8("Disabled (Fastest),2× (Faster),4× (Fast),8× (Average),16× (Slow)")), 2);